From e68f09c0e8c747474745f3438496e9352a199dbd Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 21 Nov 2012 13:11:43 +0200 Subject: Add dynamic multi-database query support --- odb/connection.ixx | 2 +- odb/database.ixx | 44 +-- odb/database.txx | 2 +- odb/details/buffer.hxx | 1 - odb/forward.hxx | 11 +- odb/function-table.hxx | 31 +- odb/makefile | 1 + odb/query-dynamic.cxx | 182 +++++++++ odb/query-dynamic.hxx | 978 +++++++++++++++++++++++++++++++++++++++++++++++++ odb/query-dynamic.ixx | 19 + odb/query-dynamic.txx | 90 +++++ odb/query.hxx | 2 +- 12 files changed, 1328 insertions(+), 35 deletions(-) create mode 100644 odb/query-dynamic.cxx create mode 100644 odb/query-dynamic.hxx create mode 100644 odb/query-dynamic.ixx create mode 100644 odb/query-dynamic.txx diff --git a/odb/connection.ixx b/odb/connection.ixx index bd91070..2ea17df 100644 --- a/odb/connection.ixx +++ b/odb/connection.ixx @@ -53,7 +53,7 @@ namespace odb inline prepared_query connection:: prepare_query (const char* n, const query& q) { - return query_::call (*this, n, q); + return query_::call (*this, n, q); } template diff --git a/odb/database.ixx b/odb/database.ixx index 5b6f876..2f39a61 100644 --- a/odb/database.ixx +++ b/odb/database.ixx @@ -73,7 +73,7 @@ namespace odb inline typename object_traits::id_type database:: persist (T& obj) { - return persist_ (obj); + return persist_ (obj); } template @@ -88,7 +88,7 @@ namespace odb // const object_pointer& pobj (p); - return persist_ (pobj); + return persist_ (pobj); } template class P> @@ -103,7 +103,7 @@ namespace odb // const object_pointer& pobj (p); - return persist_ (pobj); + return persist_ (pobj); } template class P> @@ -118,7 +118,7 @@ namespace odb // const object_pointer& pobj (p); - return persist_ (pobj); + return persist_ (pobj); } template class P> @@ -141,42 +141,42 @@ namespace odb inline typename object_traits::id_type database:: persist (const typename object_traits::pointer_type& pobj) { - return persist_ (pobj); + return persist_ (pobj); } template inline typename object_traits::pointer_type database:: load (const typename object_traits::id_type& id) { - return load_ (id); + return load_ (id); } template inline void database:: load (const typename object_traits::id_type& id, T& obj) { - return load_ (id, obj); + return load_ (id, obj); } template inline typename object_traits::pointer_type database:: find (const typename object_traits::id_type& id) { - return find_ (id); + return find_ (id); } template inline bool database:: find (const typename object_traits::id_type& id, T& obj) { - return find_ (id, obj); + return find_ (id, obj); } template inline void database:: reload (T& obj) { - reload_ (obj); + reload_ (obj); } template @@ -227,7 +227,7 @@ namespace odb inline void database:: update (T& obj) { - update_ (obj); + update_ (obj); } template @@ -242,7 +242,7 @@ namespace odb // const object_pointer& pobj (p); - update_ (pobj); + update_ (pobj); } template class P> @@ -257,7 +257,7 @@ namespace odb // const object_pointer& pobj (p); - update_ (pobj); + update_ (pobj); } template class P> @@ -272,7 +272,7 @@ namespace odb // const object_pointer& pobj (p); - update_ (pobj); + update_ (pobj); } template class P> @@ -295,21 +295,21 @@ namespace odb inline void database:: update (const typename object_traits::pointer_type& pobj) { - update_ (pobj); + update_ (pobj); } template inline void database:: erase (const typename object_traits::id_type& id) { - return erase_ (id); + return erase_ (id); } template inline void database:: erase (T& obj) { - return erase_ (obj); + return erase_ (obj); } template @@ -324,7 +324,7 @@ namespace odb // const object_pointer& pobj (p); - erase_ (pobj); + erase_ (pobj); } template class P> @@ -339,7 +339,7 @@ namespace odb // const object_pointer& pobj (p); - erase_ (pobj); + erase_ (pobj); } template class P> @@ -354,7 +354,7 @@ namespace odb // const object_pointer& pobj (p); - erase_ (pobj); + erase_ (pobj); } template class P> @@ -377,7 +377,7 @@ namespace odb inline void database:: erase (const typename object_traits::pointer_type& pobj) { - erase_ (pobj); + erase_ (pobj); } template @@ -413,7 +413,7 @@ namespace odb { // T is always object_type. // - return object_traits_impl::erase_query (*this, q); + return object_traits_impl::erase_query (*this, q); } template diff --git a/odb/database.txx b/odb/database.txx index 5556982..df58f35 100644 --- a/odb/database.txx +++ b/odb/database.txx @@ -15,7 +15,7 @@ namespace odb // T is always object_type. We also don't need to check for transaction // here; object_traits::query () does this. // - result r (query_::call (*this, q)); + result r (query_::call (*this, q)); if (cache) r.cache (); diff --git a/odb/details/buffer.hxx b/odb/details/buffer.hxx index 4556367..aeb62a3 100644 --- a/odb/details/buffer.hxx +++ b/odb/details/buffer.hxx @@ -49,7 +49,6 @@ namespace odb class basic_buffer: public basic_buffer_base { public: - basic_buffer (std::size_t capacity = 256) : basic_buffer_base (capacity) { diff --git a/odb/forward.hxx b/odb/forward.hxx index 18e0340..705acd3 100644 --- a/odb/forward.hxx +++ b/odb/forward.hxx @@ -54,13 +54,13 @@ namespace odb id_pgsql, id_oracle, id_mssql, - id_default + id_common }; // Number of real databases (i.e., excluding default) in the database_id // enum. // - const std::size_t database_count = id_default; + const std::size_t database_count = id_common; // Traits. // @@ -118,6 +118,13 @@ namespace odb // // + class query_base; + + template + struct query_column; + + // + // class result_impl; class prepared_query_impl; diff --git a/odb/function-table.hxx b/odb/function-table.hxx index b1e5987..dea68c9 100644 --- a/odb/function-table.hxx +++ b/odb/function-table.hxx @@ -12,19 +12,36 @@ namespace odb { template - struct function_table_entry + struct object_function_table_entry { - typedef access::object_traits_impl default_traits; + typedef access::object_traits_impl common_traits; - function_table_entry ( - const typename default_traits::function_table_type* t) + object_function_table_entry ( + const typename common_traits::function_table_type* t) { - default_traits::function_table[DB] = t; + common_traits::function_table[DB] = t; } - ~function_table_entry () + ~object_function_table_entry () { - default_traits::function_table[DB] = 0; + common_traits::function_table[DB] = 0; + } + }; + + template + struct view_function_table_entry + { + typedef access::view_traits_impl common_traits; + + view_function_table_entry ( + const typename common_traits::function_table_type* t) + { + common_traits::function_table[DB] = t; + } + + ~view_function_table_entry () + { + common_traits::function_table[DB] = 0; } }; } diff --git a/odb/makefile b/odb/makefile index 36100f6..c630e7c 100644 --- a/odb/makefile +++ b/odb/makefile @@ -11,6 +11,7 @@ database.cxx \ connection.cxx \ lazy-ptr-impl.cxx \ prepared-query.cxx \ +query-dynamic.cxx \ result.cxx \ schema-catalog.cxx \ session.cxx \ diff --git a/odb/query-dynamic.cxx b/odb/query-dynamic.cxx new file mode 100644 index 0000000..96aefab --- /dev/null +++ b/odb/query-dynamic.cxx @@ -0,0 +1,182 @@ +// file : odb/query-dynamic.cxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include + +using namespace std; + +namespace odb +{ + // query_param + // + query_param:: + ~query_param () + { + } + + // query_base + // + void query_base:: + clear () + { + for (clause_type::iterator i (clause_.begin ()); i != clause_.end (); ++i) + { + if (i->kind == clause_part::kind_param_val || + i->kind == clause_part::kind_param_ref) + { + query_param* qp (reinterpret_cast (i->data)); + + if (qp != 0 && qp->_dec_ref ()) + delete qp; + } + } + + clause_.clear (); + strings_.clear (); + } + + void query_base:: + append (const string& native) + { + strings_.push_back (native); + clause_.push_back (clause_part ()); + clause_.back ().kind = clause_part::kind_native; + clause_.back ().data = strings_.size () - 1; + } + + void query_base:: + append (const query_base& x) + { + size_t i (clause_.size ()), delta (i); + size_t n (i + x.clause_.size ()); + clause_.resize (n); + + for (size_t j (0); i < n; ++i, ++j) + { + const clause_part& s (x.clause_[j]); + clause_part& d (clause_[i]); + + d = s; + + // We need to increment the param references, update pointers + // to strings and update argument positions. + // + switch (s.kind) + { + case clause_part::kind_param_val: + case clause_part::kind_param_ref: + { + reinterpret_cast (d.data)->_inc_ref (); + break; + } + case clause_part::kind_native: + { + strings_.push_back (x.strings_[s.data]); + d.data = strings_.size () - 1; + break; + } + case clause_part::op_eq: + case clause_part::op_and: + { + d.data += delta; + break; + } + default: + break; + } + } + } + + void query_base:: + append_ref (const void* ref, const native_column_info* c) + { + clause_.push_back (clause_part ()); + clause_part& p (clause_.back ()); + + p.kind = clause_part::kind_param_ref; + p.data = 0; // In case new below throws. + p.native_info = c; + + p.data = reinterpret_cast ( + new (details::shared) query_param (ref)); + } + + query_base& query_base:: + operator+= (const std::string& native) + { + if (!native.empty ()) + { + size_t p (clause_.size ()); + append (native); + + if (p != 0) + append (clause_part::op_add, p - 1); + } + + return *this; + } + + query_base& query_base:: + operator+= (const query_base& x) + { + if (!x.empty ()) + { + size_t p (clause_.size ()); + append (x); + + if (p != 0) + append (clause_part::op_add, p - 1); + } + + return *this; + } + + query_base + operator&& (const query_base& x, const query_base& y) + { + // Optimize cases where one or both sides are constant truth. + // + bool xt (x.const_true ()), yt (y.const_true ()); + + if (xt && yt) + return x; + + if (xt || x.empty ()) + return y; + + if (yt || y.empty ()) + return x; + + query_base r (x); + r.append (y); + r.append (query_base::clause_part::op_and, x.clause ().size () - 1); + return r; + } + + query_base + operator|| (const query_base& x, const query_base& y) + { + if (x.empty ()) + return y; + + if (y.empty ()) + return x; + + query_base r (x); + r.append (y); + r.append (query_base::clause_part::op_or, x.clause ().size () - 1); + return r; + } + + query_base + operator! (const query_base& x) + { + if (x.empty ()) + return x; + + query_base r (x); + r.append (query_base::clause_part::op_not, 0); + return r; + } +} diff --git a/odb/query-dynamic.hxx b/odb/query-dynamic.hxx new file mode 100644 index 0000000..ed32ec9 --- /dev/null +++ b/odb/query-dynamic.hxx @@ -0,0 +1,978 @@ +// file : odb/query-dynamic.hxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_QUERY_DYNAMIC_HXX +#define ODB_QUERY_DYNAMIC_HXX + +#include + +#include +#include +#include // std::size_t + +#include +#include + +#include +#include + +namespace odb +{ + struct native_column_info; + + template + struct val_bind + { + explicit + val_bind (const T& v): val (v) {} + + const T& val; + }; + + template + struct ref_bind + { + explicit + ref_bind (const T& r): ref (r) {} + + const T& ref; + }; + + // + // + struct LIBODB_EXPORT query_param: details::shared_base + { + virtual ~query_param (); + query_param (const void* v): value (v) {} + + const void* value; + }; + + // For by-value parameters we have to make a copy since the original + // can be gone by the time we translate to native query. + // + template + struct val_query_param: query_param + { + val_query_param (const T& v): query_param (©), copy (v) {} + + T copy; + }; + + // + // + class LIBODB_EXPORT query_base + { + public: + // Internally the query clause is stored in a Reverse Polish Notation- + // like representation which also allows us to traverse it as a syntax + // tree. + // + // Let's keep this class POD so that std::vector can do more + // efficient copying, etc. + // + struct clause_part + { + // Note that the order of enumerators is important (used as indexes). + // + enum kind_type + { + kind_column, // native_info points to the native_column_info array. + + kind_param_val, // data points to query_param while native_info points + kind_param_ref, // to the native_column_info array. + + kind_native, // data is the index in the strings vector. + + kind_true, // true literal. + kind_false, // false literal. + + // Operators. + // + // For binary operators, data is the index of the last element + // belonging to the left hand side sub-expression. + // + op_add, // + (concatenation of two sub-expressions) + + op_and, // && + op_or, // || + op_not, // ! + + op_null, // is_null () + op_not_null, // is_not_null () + + op_in, // in(), data is the number of arguments + + op_eq, // == + op_ne, // != + op_lt, // < + op_gt, // > + op_le, // <= + op_ge // >= + }; + + kind_type kind; + std::size_t data; + const native_column_info* native_info; + }; + + public: + ~query_base () + { + clear (); + } + + query_base () {} + + // True or false literal. + // + explicit + query_base (bool v) + { + append (v ? clause_part::kind_true : clause_part::kind_false, 0); + } + + explicit + query_base (const char* native) + { + append (native); + } + + explicit + query_base (const std::string& native) + { + append (native); + } + + query_base (const query_column&); + + query_base (const query_base& x) + { + append (x); + } + + query_base& + operator= (const query_base& x) + { + if (this != &x) + { + clear (); + append (x); + } + + return *this; + } + + 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_base& + operator+= (const query_base&); + + query_base& + operator+= (const std::string& native); + + public: + bool + empty () const + { + return clause_.empty (); + } + + bool + const_true () const + { + return clause_.size () == 1 && + clause_.front ().kind == clause_part::kind_true; + } + + // Implementation details. + // + public: + explicit + query_base (const native_column_info* c) + { + append (c); + } + + // Native. + // + void + append (const std::string&); + + // Query fragment. + // + void + append (const query_base&); + + // Operator. + // + void + append (clause_part::kind_type k, std::size_t data) + { + clause_.push_back (clause_part ()); + clause_.back ().kind = k; + clause_.back ().data = data; + } + + // Column. + // + void + append (const native_column_info* c) + { + clause_.push_back (clause_part ()); + clause_.back ().kind = clause_part::kind_column; + clause_.back ().native_info = c; + } + + // Parameter. + // + void + append_ref (const void* ref, const native_column_info*); + + template + void + append_val (const T& val, const native_column_info*); + + void + clear (); + + public: + typedef std::vector clause_type; + typedef std::vector strings_type; + + const clause_type& + clause () const + { + return clause_; + } + + const strings_type& + strings () const + { + return strings_; + } + + private: + clause_type clause_; + strings_type strings_; + }; + + inline query_base + operator+ (const query_base& x, const query_base& y) + { + query_base r (x); + r += y; + return r; + } + + inline query_base + operator+ (const query_base& q, const std::string& s) + { + query_base r (q); + r += s; + return r; + } + + inline query_base + operator+ (const std::string& s, const query_base& q) + { + query_base r (s); + r += q; + return r; + } + + LIBODB_EXPORT query_base + operator&& (const query_base&, const query_base&); + + LIBODB_EXPORT query_base + operator|| (const query_base&, const query_base&); + + LIBODB_EXPORT query_base + operator! (const query_base&); + + // + // + struct native_column_info + { + const void* column; + void* param_factory; + }; + + template + const T& + type_instance (); + + // This class template has to remain POD since we rely on it being + // 0-initialized before any dynamic initialization takes place in + // any other translation unit. + // + template + struct query_column + { + // Array of pointers to database-specific columns. It will be + // automatically zero-initialized since query_column instances + // are always static. + // + native_column_info native_info[database_count]; + + // is_null, is_not_null + // + public: + query_base + is_null () const + { + query_base q (native_info); + q.append (query_base::clause_part::op_null, 0); + return q; + } + + query_base + is_not_null () const + { + query_base q (native_info); + q.append (query_base::clause_part::op_not_null, 0); + return q; + } + + // in + // + public: + query_base + in (const T&, const T&) const; + + query_base + in (const T&, const T&, const T&) const; + + query_base + in (const T&, const T&, const T&, const T&) const; + + query_base + in (const T&, const T&, const T&, const T&, const T&) const; + + template + query_base + in_range (I begin, I end) const; + + // == + // + public: + query_base + equal (val_bind v) const + { + query_base q (native_info); + q.append_val (v.val, native_info); + q.append (query_base::clause_part::op_eq, 0); + return q; + } + + query_base + equal (ref_bind r) const + { + query_base q (native_info); + q.append_ref (&r.ref, native_info); + q.append (query_base::clause_part::op_eq, 0); + return q; + } + + friend query_base + operator== (const query_column& c, const T& v) + { + return c.equal (val_bind (v)); + } + + friend query_base + operator== (const T& v, const query_column& c) + { + return c.equal (val_bind (v)); + } + + friend query_base + operator== (const query_column& c, val_bind v) + { + return c.equal (v); + } + + friend query_base + operator== (val_bind v, const query_column& c) + { + return c.equal (v); + } + + template + friend query_base + operator== (const query_column& c, val_bind v) + { + return c.equal (val_bind (T (v.val))); + } + + template + friend query_base + operator== (val_bind v, const query_column& c) + { + return c.equal (val_bind (T (v.val))); + } + + friend query_base + operator== (const query_column& c, ref_bind r) + { + return c.equal (r); + } + + friend query_base + operator== (ref_bind r, const query_column& c) + { + return c.equal (r); + } + + // != + // + public: + query_base + unequal (val_bind v) const + { + query_base q (native_info); + q.append_val (v.val, native_info); + q.append (query_base::clause_part::op_ne, 0); + return q; + } + + query_base + unequal (ref_bind r) const + { + query_base q (native_info); + q.append_ref (&r.ref, native_info); + q.append (query_base::clause_part::op_ne, 0); + return q; + } + + friend query_base + operator!= (const query_column& c, const T& v) + { + return c.unequal (val_bind (v)); + } + + friend query_base + operator!= (const T& v, const query_column& c) + { + return c.unequal (val_bind (v)); + } + + friend query_base + operator!= (const query_column& c, val_bind v) + { + return c.unequal (v); + } + + friend query_base + operator!= (val_bind v, const query_column& c) + { + return c.unequal (v); + } + + template + friend query_base + operator!= (const query_column& c, val_bind v) + { + return c.unequal (val_bind (T (v.val))); + } + + template + friend query_base + operator!= (val_bind v, const query_column& c) + { + return c.unequal (val_bind (T (v.val))); + } + + friend query_base + operator!= (const query_column& c, ref_bind r) + { + return c.unequal (r); + } + + friend query_base + operator!= (ref_bind r, const query_column& c) + { + return c.unequal (r); + } + + // < + // + public: + query_base + less (val_bind v) const + { + query_base q (native_info); + q.append_val (v.val, native_info); + q.append (query_base::clause_part::op_lt, 0); + return q; + } + + query_base + less (ref_bind r) const + { + query_base q (native_info); + q.append_ref (&r.ref, native_info); + q.append (query_base::clause_part::op_lt, 0); + return q; + } + + friend query_base + operator< (const query_column& c, const T& v) + { + return c.less (val_bind (v)); + } + + friend query_base + operator< (const T& v, const query_column& c) + { + return c.greater (val_bind (v)); + } + + friend query_base + operator< (const query_column& c, val_bind v) + { + return c.less (v); + } + + friend query_base + operator< (val_bind v, const query_column& c) + { + return c.greater (v); + } + + template + friend query_base + operator< (const query_column& c, val_bind v) + { + return c.less (val_bind (T (v.val))); + } + + template + friend query_base + operator< (val_bind v, const query_column& c) + { + return c.greater (val_bind (T (v.val))); + } + + friend query_base + operator< (const query_column& c, ref_bind r) + { + return c.less (r); + } + + friend query_base + operator< (ref_bind r, const query_column& c) + { + return c.greater (r); + } + + // > + // + public: + query_base + greater (val_bind v) const + { + query_base q (native_info); + q.append_val (v.val, native_info); + q.append (query_base::clause_part::op_gt, 0); + return q; + } + + query_base + greater (ref_bind r) const + { + query_base q (native_info); + q.append_ref (&r.ref, native_info); + q.append (query_base::clause_part::op_gt, 0); + return q; + } + + friend query_base + operator> (const query_column& c, const T& v) + { + return c.greater (val_bind (v)); + } + + friend query_base + operator> (const T& v, const query_column& c) + { + return c.less (val_bind (v)); + } + + friend query_base + operator> (const query_column& c, val_bind v) + { + return c.greater (v); + } + + friend query_base + operator> (val_bind v, const query_column& c) + { + return c.less (v); + } + + template + friend query_base + operator> (const query_column& c, val_bind v) + { + return c.greater (val_bind (T (v.val))); + } + + template + friend query_base + operator> (val_bind v, const query_column& c) + { + return c.less (val_bind (T (v.val))); + } + + friend query_base + operator> (const query_column& c, ref_bind r) + { + return c.greater (r); + } + + friend query_base + operator> (ref_bind r, const query_column& c) + { + return c.less (r); + } + + // <= + // + public: + query_base + less_equal (val_bind v) const + { + query_base q (native_info); + q.append_val (v.val, native_info); + q.append (query_base::clause_part::op_le, 0); + return q; + } + + query_base + less_equal (ref_bind r) const + { + query_base q (native_info); + q.append_ref (&r.ref, native_info); + q.append (query_base::clause_part::op_le, 0); + return q; + } + + friend query_base + operator<= (const query_column& c, const T& v) + { + return c.less_equal (val_bind (v)); + } + + friend query_base + operator<= (const T& v, const query_column& c) + { + return c.greater_equal (val_bind (v)); + } + + friend query_base + operator<= (const query_column& c, val_bind v) + { + return c.less_equal (v); + } + + friend query_base + operator<= (val_bind v, const query_column& c) + { + return c.greater_equal (v); + } + + template + friend query_base + operator<= (const query_column& c, val_bind v) + { + return c.less_equal (val_bind (T (v.val))); + } + + template + friend query_base + operator<= (val_bind v, const query_column& c) + { + return c.greater_equal (val_bind (T (v.val))); + } + + friend query_base + operator<= (const query_column& c, ref_bind r) + { + return c.less_equal (r); + } + + friend query_base + operator<= (ref_bind r, const query_column& c) + { + return c.greater_equal (r); + } + + // >= + // + public: + query_base + greater_equal (val_bind v) const + { + query_base q (native_info); + q.append_val (v.val, native_info); + q.append (query_base::clause_part::op_ge, 0); + return q; + } + + query_base + greater_equal (ref_bind r) const + { + query_base q (native_info); + q.append_ref (&r.ref, native_info); + q.append (query_base::clause_part::op_ge, 0); + return q; + } + + friend query_base + operator>= (const query_column& c, const T& v) + { + return c.greater_equal (val_bind (v)); + } + + friend query_base + operator>= (const T& v, const query_column& c) + { + return c.less_equal (val_bind (v)); + } + + friend query_base + operator>= (const query_column& c, val_bind v) + { + return c.greater_equal (v); + } + + friend query_base + operator>= (val_bind v, const query_column& c) + { + return c.less_equal (v); + } + + template + friend query_base + operator>= (const query_column& c, val_bind v) + { + return c.greater_equal (val_bind (T (v.val))); + } + + template + friend query_base + operator>= (val_bind v, const query_column& c) + { + return c.less_equal (val_bind (T (v.val))); + } + + friend query_base + operator>= (const query_column& c, ref_bind r) + { + return c.greater_equal (r); + } + + friend query_base + operator>= (ref_bind r, const query_column& c) + { + return c.less_equal (r); + } + + // Column comparison. + // + public: + template + query_base + operator== (const query_column& c) const + { + // We can compare columns only if we can compare their C++ types. + // + (void) (sizeof (type_instance () == type_instance ())); + + query_base q (native_info); + q.append (c.native_info); + q.append (query_base::clause_part::op_eq, 0); + return q; + } + + template + query_base + operator!= (const query_column& c) const + { + // We can compare columns only if we can compare their C++ types. + // + (void) (sizeof (type_instance () != type_instance ())); + + query_base q (native_info); + q.append (c.native_info); + q.append (query_base::clause_part::op_ne, 0); + return q; + } + + template + query_base + operator< (const query_column& c) const + { + // We can compare columns only if we can compare their C++ types. + // + (void) (sizeof (type_instance () < type_instance ())); + + query_base q (native_info); + q.append (c.native_info); + q.append (query_base::clause_part::op_lt, 0); + return q; + } + + template + query_base + operator> (const query_column& c) const + { + // We can compare columns only if we can compare their C++ types. + // + (void) (sizeof (type_instance () > type_instance ())); + + query_base q (native_info); + q.append (c.native_info); + q.append (query_base::clause_part::op_gt, 0); + return q; + } + + template + query_base + operator<= (const query_column& c) const + { + // We can compare columns only if we can compare their C++ types. + // + (void) (sizeof (type_instance () <= type_instance ())); + + query_base q (native_info); + q.append (c.native_info); + q.append (query_base::clause_part::op_le, 0); + return q; + } + + template + query_base + operator>= (const query_column& c) const + { + // We can compare columns only if we can compare their C++ types. + // + (void) (sizeof (type_instance () >= type_instance ())); + + query_base q (native_info); + q.append (c.native_info); + q.append (query_base::clause_part::op_ge, 0); + return q; + } + }; + + // Provide operator+() for using columns to construct native + // query fragments (e.g., ORDER BY). + // + template + inline query_base + operator+ (const query_column& c, const std::string& s) + { + query_base q (c.native_info); + q.append (s); + q.append (query_base::clause_part::op_add, 0); + return q; + } + + template + inline query_base + operator+ (const std::string& s, const query_column& c) + { + query_base q (s); + q.append (c.native_info); + q.append (query_base::clause_part::op_add, 0); + return q; + } + + template + inline query_base + operator+ (const query_column& c, const query_base& q) + { + query_base r (c.native_info); + r.append (q); + r.append (query_base::clause_part::op_add, 0); + return r; + } + + template + inline query_base + operator+ (const query_base& q, const query_column& c) + { + query_base r (q); + r.append (c.native_info); + r.append (query_base::clause_part::op_add, q.clause ().size () - 1); + return r; + } + + // + // + template + class query: public query_base, + public query_selector::columns_type + { + public: + // We don't define any typedefs here since they may clash with + // column names defined by our base type. + // + + query () + { + } + + explicit + query (bool v) + : query_base (v) + { + } + + explicit + query (const char* q) + : query_base (q) + { + } + + explicit + query (const std::string& q) + : query_base (q) + { + } + + query (const query_base& q) + : query_base (q) + { + } + + query (const query_column& qc) + : query_base (qc) + { + } + }; +} + +#include +#include + +#include + +#endif // ODB_QUERY_DYNAMIC_HXX diff --git a/odb/query-dynamic.ixx b/odb/query-dynamic.ixx new file mode 100644 index 0000000..a6250be --- /dev/null +++ b/odb/query-dynamic.ixx @@ -0,0 +1,19 @@ +// file : odb/query-dynamic.ixx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +namespace odb +{ + // query_base + // + inline query_base:: + query_base (const query_column& c) + { + // Some databases provide the IS TRUE operator. However, we cannot + // use it since the column type might now be SQL boolean type. + // + append (c.native_info); + append_val (true, c.native_info); + append (query_base::clause_part::op_eq, 0); + } +} diff --git a/odb/query-dynamic.txx b/odb/query-dynamic.txx new file mode 100644 index 0000000..cf7401d --- /dev/null +++ b/odb/query-dynamic.txx @@ -0,0 +1,90 @@ +// file : odb/query-dynamic.txx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +namespace odb +{ + // query_base + // + template + void query_base:: + append_val (const T& val, const native_column_info* c) + { + clause_.push_back (clause_part ()); + clause_part& p (clause_.back ()); + + p.kind = clause_part::kind_param_val; + p.data = 0; // In case new below throws. + p.native_info = c; + + query_param* qp (new (details::shared) val_query_param (val)); + p.data = reinterpret_cast (qp); + } + + // query_column + // + template + query_base query_column:: + in (const T& v1, const T& v2) const + { + query_base q (native_info); + q.append_val (v1, native_info); + q.append_val (v2, native_info); + q.append (query_base::clause_part::op_in, 2); + return q; + } + + template + query_base query_column:: + in (const T& v1, const T& v2, const T& v3) const + { + query_base q (native_info); + q.append_val (v1, native_info); + q.append_val (v2, native_info); + q.append_val (v3, native_info); + q.append (query_base::clause_part::op_in, 3); + return q; + } + + template + query_base query_column:: + in (const T& v1, const T& v2, const T& v3, const T& v4) const + { + query_base q (native_info); + q.append_val (v1, native_info); + q.append_val (v2, native_info); + q.append_val (v3, native_info); + q.append_val (v4, native_info); + q.append (query_base::clause_part::op_in, 4); + return q; + } + + template + query_base query_column:: + in (const T& v1, const T& v2, const T& v3, const T& v4, const T& v5) const + { + query_base q (native_info); + q.append_val (v1, native_info); + q.append_val (v2, native_info); + q.append_val (v3, native_info); + q.append_val (v4, native_info); + q.append_val (v5, native_info); + q.append (query_base::clause_part::op_in, 5); + return q; + } + + template + template + query_base query_column:: + in_range (I i, I end) const + { + query_base q (native_info); + + std::size_t n (0); + for (; i != end; ++i, ++n) + q.append_val (*i, native_info); + + q.append (query_base::clause_part::op_in, n); + return q; + } +} diff --git a/odb/query.hxx b/odb/query.hxx index ffff7f7..adea4b3 100644 --- a/odb/query.hxx +++ b/odb/query.hxx @@ -82,7 +82,7 @@ namespace odb }; template ::base_type> + typename B = typename query_selector::base_type> class query; namespace core -- cgit v1.1