aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2012-11-21 13:11:43 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2012-11-21 13:11:43 +0200
commite68f09c0e8c747474745f3438496e9352a199dbd (patch)
treeb609371a129df96147aa77fc838ceca39b8be533
parentfd5ba96357002c0964453fea38ee6a813cf02826 (diff)
Add dynamic multi-database query support
-rw-r--r--odb/connection.ixx2
-rw-r--r--odb/database.ixx44
-rw-r--r--odb/database.txx2
-rw-r--r--odb/details/buffer.hxx1
-rw-r--r--odb/forward.hxx11
-rw-r--r--odb/function-table.hxx31
-rw-r--r--odb/makefile1
-rw-r--r--odb/query-dynamic.cxx182
-rw-r--r--odb/query-dynamic.hxx978
-rw-r--r--odb/query-dynamic.ixx19
-rw-r--r--odb/query-dynamic.txx90
-rw-r--r--odb/query.hxx2
12 files changed, 1328 insertions, 35 deletions
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<T> connection::
prepare_query (const char* n, const query<T>& q)
{
- return query_<T, id_default>::call (*this, n, q);
+ return query_<T, id_common>::call (*this, n, q);
}
template <typename T>
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<T>::id_type database::
persist (T& obj)
{
- return persist_<T, id_default> (obj);
+ return persist_<T, id_common> (obj);
}
template <typename T>
@@ -88,7 +88,7 @@ namespace odb
//
const object_pointer& pobj (p);
- return persist_<T, id_default> (pobj);
+ return persist_<T, id_common> (pobj);
}
template <typename T, template <typename> class P>
@@ -103,7 +103,7 @@ namespace odb
//
const object_pointer& pobj (p);
- return persist_<T, id_default> (pobj);
+ return persist_<T, id_common> (pobj);
}
template <typename T, typename A1, template <typename, typename> class P>
@@ -118,7 +118,7 @@ namespace odb
//
const object_pointer& pobj (p);
- return persist_<T, id_default> (pobj);
+ return persist_<T, id_common> (pobj);
}
template <typename T, template <typename> class P>
@@ -141,42 +141,42 @@ namespace odb
inline typename object_traits<T>::id_type database::
persist (const typename object_traits<T>::pointer_type& pobj)
{
- return persist_<T, id_default> (pobj);
+ return persist_<T, id_common> (pobj);
}
template <typename T>
inline typename object_traits<T>::pointer_type database::
load (const typename object_traits<T>::id_type& id)
{
- return load_<T, id_default> (id);
+ return load_<T, id_common> (id);
}
template <typename T>
inline void database::
load (const typename object_traits<T>::id_type& id, T& obj)
{
- return load_<T, id_default> (id, obj);
+ return load_<T, id_common> (id, obj);
}
template <typename T>
inline typename object_traits<T>::pointer_type database::
find (const typename object_traits<T>::id_type& id)
{
- return find_<T, id_default> (id);
+ return find_<T, id_common> (id);
}
template <typename T>
inline bool database::
find (const typename object_traits<T>::id_type& id, T& obj)
{
- return find_<T, id_default> (id, obj);
+ return find_<T, id_common> (id, obj);
}
template <typename T>
inline void database::
reload (T& obj)
{
- reload_<T, id_default> (obj);
+ reload_<T, id_common> (obj);
}
template <typename T>
@@ -227,7 +227,7 @@ namespace odb
inline void database::
update (T& obj)
{
- update_<T, id_default> (obj);
+ update_<T, id_common> (obj);
}
template <typename T>
@@ -242,7 +242,7 @@ namespace odb
//
const object_pointer& pobj (p);
- update_<T, id_default> (pobj);
+ update_<T, id_common> (pobj);
}
template <typename T, template <typename> class P>
@@ -257,7 +257,7 @@ namespace odb
//
const object_pointer& pobj (p);
- update_<T, id_default> (pobj);
+ update_<T, id_common> (pobj);
}
template <typename T, typename A1, template <typename, typename> class P>
@@ -272,7 +272,7 @@ namespace odb
//
const object_pointer& pobj (p);
- update_<T, id_default> (pobj);
+ update_<T, id_common> (pobj);
}
template <typename T, template <typename> class P>
@@ -295,21 +295,21 @@ namespace odb
inline void database::
update (const typename object_traits<T>::pointer_type& pobj)
{
- update_<T, id_default> (pobj);
+ update_<T, id_common> (pobj);
}
template <typename T>
inline void database::
erase (const typename object_traits<T>::id_type& id)
{
- return erase_<T, id_default> (id);
+ return erase_<T, id_common> (id);
}
template <typename T>
inline void database::
erase (T& obj)
{
- return erase_<T, id_default> (obj);
+ return erase_<T, id_common> (obj);
}
template <typename T>
@@ -324,7 +324,7 @@ namespace odb
//
const object_pointer& pobj (p);
- erase_<T, id_default> (pobj);
+ erase_<T, id_common> (pobj);
}
template <typename T, template <typename> class P>
@@ -339,7 +339,7 @@ namespace odb
//
const object_pointer& pobj (p);
- erase_<T, id_default> (pobj);
+ erase_<T, id_common> (pobj);
}
template <typename T, typename A1, template <typename, typename> class P>
@@ -354,7 +354,7 @@ namespace odb
//
const object_pointer& pobj (p);
- erase_<T, id_default> (pobj);
+ erase_<T, id_common> (pobj);
}
template <typename T, template <typename> class P>
@@ -377,7 +377,7 @@ namespace odb
inline void database::
erase (const typename object_traits<T>::pointer_type& pobj)
{
- erase_<T, id_default> (pobj);
+ erase_<T, id_common> (pobj);
}
template <typename T>
@@ -413,7 +413,7 @@ namespace odb
{
// T is always object_type.
//
- return object_traits_impl<T, id_default>::erase_query (*this, q);
+ return object_traits_impl<T, id_common>::erase_query (*this, q);
}
template <typename T>
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<T> r (query_<T, id_default>::call (*this, q));
+ result<T> r (query_<T, id_common>::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 <typename T>
+ 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 <typename T, database_id DB>
- struct function_table_entry
+ struct object_function_table_entry
{
- typedef access::object_traits_impl<T, id_default> default_traits;
+ typedef access::object_traits_impl<T, id_common> 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 <typename T, database_id DB>
+ struct view_function_table_entry
+ {
+ typedef access::view_traits_impl<T, id_common> 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 <odb/query-dynamic.hxx>
+
+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<query_param*> (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<query_param*> (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<std::size_t> (
+ 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 <odb/pre.hxx>
+
+#include <string>
+#include <vector>
+#include <cstddef> // std::size_t
+
+#include <odb/forward.hxx>
+#include <odb/query.hxx>
+
+#include <odb/details/export.hxx>
+#include <odb/details/shared-ptr.hxx>
+
+namespace odb
+{
+ struct native_column_info;
+
+ template <typename T>
+ struct val_bind
+ {
+ explicit
+ val_bind (const T& v): val (v) {}
+
+ const T& val;
+ };
+
+ template <typename T>
+ 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 <typename T>
+ struct val_query_param: query_param
+ {
+ val_query_param (const T& v): query_param (&copy), 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<bool>&);
+
+ 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 <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_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 <typename T>
+ void
+ append_val (const T& val, const native_column_info*);
+
+ void
+ clear ();
+
+ public:
+ typedef std::vector<clause_part> clause_type;
+ typedef std::vector<std::string> 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 <typename T>
+ 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 <typename T>
+ 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 <typename I>
+ query_base
+ in_range (I begin, I end) const;
+
+ // ==
+ //
+ public:
+ query_base
+ equal (val_bind<T> 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<T> 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<T> (v));
+ }
+
+ friend query_base
+ operator== (const T& v, const query_column& c)
+ {
+ return c.equal (val_bind<T> (v));
+ }
+
+ friend query_base
+ operator== (const query_column& c, val_bind<T> v)
+ {
+ return c.equal (v);
+ }
+
+ friend query_base
+ operator== (val_bind<T> v, const query_column& c)
+ {
+ return c.equal (v);
+ }
+
+ template <typename T2>
+ friend query_base
+ operator== (const query_column& c, val_bind<T2> v)
+ {
+ return c.equal (val_bind<T> (T (v.val)));
+ }
+
+ template <typename T2>
+ friend query_base
+ operator== (val_bind<T2> v, const query_column& c)
+ {
+ return c.equal (val_bind<T> (T (v.val)));
+ }
+
+ friend query_base
+ operator== (const query_column& c, ref_bind<T> r)
+ {
+ return c.equal (r);
+ }
+
+ friend query_base
+ operator== (ref_bind<T> r, const query_column& c)
+ {
+ return c.equal (r);
+ }
+
+ // !=
+ //
+ public:
+ query_base
+ unequal (val_bind<T> 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<T> 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<T> (v));
+ }
+
+ friend query_base
+ operator!= (const T& v, const query_column& c)
+ {
+ return c.unequal (val_bind<T> (v));
+ }
+
+ friend query_base
+ operator!= (const query_column& c, val_bind<T> v)
+ {
+ return c.unequal (v);
+ }
+
+ friend query_base
+ operator!= (val_bind<T> v, const query_column& c)
+ {
+ return c.unequal (v);
+ }
+
+ template <typename T2>
+ friend query_base
+ operator!= (const query_column& c, val_bind<T2> v)
+ {
+ return c.unequal (val_bind<T> (T (v.val)));
+ }
+
+ template <typename T2>
+ friend query_base
+ operator!= (val_bind<T2> v, const query_column& c)
+ {
+ return c.unequal (val_bind<T> (T (v.val)));
+ }
+
+ friend query_base
+ operator!= (const query_column& c, ref_bind<T> r)
+ {
+ return c.unequal (r);
+ }
+
+ friend query_base
+ operator!= (ref_bind<T> r, const query_column& c)
+ {
+ return c.unequal (r);
+ }
+
+ // <
+ //
+ public:
+ query_base
+ less (val_bind<T> 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<T> 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<T> (v));
+ }
+
+ friend query_base
+ operator< (const T& v, const query_column& c)
+ {
+ return c.greater (val_bind<T> (v));
+ }
+
+ friend query_base
+ operator< (const query_column& c, val_bind<T> v)
+ {
+ return c.less (v);
+ }
+
+ friend query_base
+ operator< (val_bind<T> v, const query_column& c)
+ {
+ return c.greater (v);
+ }
+
+ template <typename T2>
+ friend query_base
+ operator< (const query_column& c, val_bind<T2> v)
+ {
+ return c.less (val_bind<T> (T (v.val)));
+ }
+
+ template <typename T2>
+ friend query_base
+ operator< (val_bind<T2> v, const query_column& c)
+ {
+ return c.greater (val_bind<T> (T (v.val)));
+ }
+
+ friend query_base
+ operator< (const query_column& c, ref_bind<T> r)
+ {
+ return c.less (r);
+ }
+
+ friend query_base
+ operator< (ref_bind<T> r, const query_column& c)
+ {
+ return c.greater (r);
+ }
+
+ // >
+ //
+ public:
+ query_base
+ greater (val_bind<T> 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<T> 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<T> (v));
+ }
+
+ friend query_base
+ operator> (const T& v, const query_column& c)
+ {
+ return c.less (val_bind<T> (v));
+ }
+
+ friend query_base
+ operator> (const query_column& c, val_bind<T> v)
+ {
+ return c.greater (v);
+ }
+
+ friend query_base
+ operator> (val_bind<T> v, const query_column& c)
+ {
+ return c.less (v);
+ }
+
+ template <typename T2>
+ friend query_base
+ operator> (const query_column& c, val_bind<T2> v)
+ {
+ return c.greater (val_bind<T> (T (v.val)));
+ }
+
+ template <typename T2>
+ friend query_base
+ operator> (val_bind<T2> v, const query_column& c)
+ {
+ return c.less (val_bind<T> (T (v.val)));
+ }
+
+ friend query_base
+ operator> (const query_column& c, ref_bind<T> r)
+ {
+ return c.greater (r);
+ }
+
+ friend query_base
+ operator> (ref_bind<T> r, const query_column& c)
+ {
+ return c.less (r);
+ }
+
+ // <=
+ //
+ public:
+ query_base
+ less_equal (val_bind<T> 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<T> 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<T> (v));
+ }
+
+ friend query_base
+ operator<= (const T& v, const query_column& c)
+ {
+ return c.greater_equal (val_bind<T> (v));
+ }
+
+ friend query_base
+ operator<= (const query_column& c, val_bind<T> v)
+ {
+ return c.less_equal (v);
+ }
+
+ friend query_base
+ operator<= (val_bind<T> v, const query_column& c)
+ {
+ return c.greater_equal (v);
+ }
+
+ template <typename T2>
+ friend query_base
+ operator<= (const query_column& c, val_bind<T2> v)
+ {
+ return c.less_equal (val_bind<T> (T (v.val)));
+ }
+
+ template <typename T2>
+ friend query_base
+ operator<= (val_bind<T2> v, const query_column& c)
+ {
+ return c.greater_equal (val_bind<T> (T (v.val)));
+ }
+
+ friend query_base
+ operator<= (const query_column& c, ref_bind<T> r)
+ {
+ return c.less_equal (r);
+ }
+
+ friend query_base
+ operator<= (ref_bind<T> r, const query_column& c)
+ {
+ return c.greater_equal (r);
+ }
+
+ // >=
+ //
+ public:
+ query_base
+ greater_equal (val_bind<T> 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<T> 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<T> (v));
+ }
+
+ friend query_base
+ operator>= (const T& v, const query_column& c)
+ {
+ return c.less_equal (val_bind<T> (v));
+ }
+
+ friend query_base
+ operator>= (const query_column& c, val_bind<T> v)
+ {
+ return c.greater_equal (v);
+ }
+
+ friend query_base
+ operator>= (val_bind<T> v, const query_column& c)
+ {
+ return c.less_equal (v);
+ }
+
+ template <typename T2>
+ friend query_base
+ operator>= (const query_column& c, val_bind<T2> v)
+ {
+ return c.greater_equal (val_bind<T> (T (v.val)));
+ }
+
+ template <typename T2>
+ friend query_base
+ operator>= (val_bind<T2> v, const query_column& c)
+ {
+ return c.less_equal (val_bind<T> (T (v.val)));
+ }
+
+ friend query_base
+ operator>= (const query_column& c, ref_bind<T> r)
+ {
+ return c.greater_equal (r);
+ }
+
+ friend query_base
+ operator>= (ref_bind<T> r, const query_column& c)
+ {
+ return c.less_equal (r);
+ }
+
+ // Column comparison.
+ //
+ public:
+ template <typename T2>
+ query_base
+ operator== (const query_column<T2>& c) const
+ {
+ // We can compare columns only if we can compare their C++ types.
+ //
+ (void) (sizeof (type_instance<T> () == type_instance<T2> ()));
+
+ query_base q (native_info);
+ q.append (c.native_info);
+ q.append (query_base::clause_part::op_eq, 0);
+ return q;
+ }
+
+ template <typename T2>
+ query_base
+ operator!= (const query_column<T2>& c) const
+ {
+ // We can compare columns only if we can compare their C++ types.
+ //
+ (void) (sizeof (type_instance<T> () != type_instance<T2> ()));
+
+ query_base q (native_info);
+ q.append (c.native_info);
+ q.append (query_base::clause_part::op_ne, 0);
+ return q;
+ }
+
+ template <typename T2>
+ query_base
+ operator< (const query_column<T2>& c) const
+ {
+ // We can compare columns only if we can compare their C++ types.
+ //
+ (void) (sizeof (type_instance<T> () < type_instance<T2> ()));
+
+ query_base q (native_info);
+ q.append (c.native_info);
+ q.append (query_base::clause_part::op_lt, 0);
+ return q;
+ }
+
+ template <typename T2>
+ query_base
+ operator> (const query_column<T2>& c) const
+ {
+ // We can compare columns only if we can compare their C++ types.
+ //
+ (void) (sizeof (type_instance<T> () > type_instance<T2> ()));
+
+ query_base q (native_info);
+ q.append (c.native_info);
+ q.append (query_base::clause_part::op_gt, 0);
+ return q;
+ }
+
+ template <typename T2>
+ query_base
+ operator<= (const query_column<T2>& c) const
+ {
+ // We can compare columns only if we can compare their C++ types.
+ //
+ (void) (sizeof (type_instance<T> () <= type_instance<T2> ()));
+
+ query_base q (native_info);
+ q.append (c.native_info);
+ q.append (query_base::clause_part::op_le, 0);
+ return q;
+ }
+
+ template <typename T2>
+ query_base
+ operator>= (const query_column<T2>& c) const
+ {
+ // We can compare columns only if we can compare their C++ types.
+ //
+ (void) (sizeof (type_instance<T> () >= type_instance<T2> ()));
+
+ 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 <typename T>
+ inline query_base
+ operator+ (const query_column<T>& 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 <typename T>
+ inline query_base
+ operator+ (const std::string& s, const query_column<T>& c)
+ {
+ query_base q (s);
+ q.append (c.native_info);
+ q.append (query_base::clause_part::op_add, 0);
+ return q;
+ }
+
+ template <typename T>
+ inline query_base
+ operator+ (const query_column<T>& 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 <typename T>
+ inline query_base
+ operator+ (const query_base& q, const query_column<T>& 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 <typename T>
+ class query<T, query_base>: public query_base,
+ public query_selector<T, id_common>::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<bool>& qc)
+ : query_base (qc)
+ {
+ }
+ };
+}
+
+#include <odb/query-dynamic.ixx>
+#include <odb/query-dynamic.txx>
+
+#include <odb/post.hxx>
+
+#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<bool>& 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 <typename T>
+ 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<T> (val));
+ p.data = reinterpret_cast<std::size_t> (qp);
+ }
+
+ // query_column
+ //
+ template <typename T>
+ query_base query_column<T>::
+ 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 <typename T>
+ query_base query_column<T>::
+ 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 <typename T>
+ query_base query_column<T>::
+ 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 <typename T>
+ query_base query_column<T>::
+ 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 <typename T>
+ template <typename I>
+ query_base query_column<T>::
+ 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 <typename T,
- typename B = typename query_selector<T, id_default>::base_type>
+ typename B = typename query_selector<T, id_common>::base_type>
class query;
namespace core