diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2012-11-21 13:11:43 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2012-11-21 13:11:43 +0200 |
commit | a2914e837c6442db936fd035b49f60ee488df533 (patch) | |
tree | 112ef78437897d22148d07292a19a15b7fd8a58b | |
parent | 14d0ecab529bc46ebadd319cd4dbc1c99bb53e6b (diff) |
Add dynamic multi-database query support
-rw-r--r-- | odb/sqlite/makefile | 1 | ||||
-rw-r--r-- | odb/sqlite/query-dynamic.cxx | 136 | ||||
-rw-r--r-- | odb/sqlite/query-dynamic.hxx | 33 | ||||
-rw-r--r-- | odb/sqlite/query-dynamic.ixx | 27 | ||||
-rw-r--r-- | odb/sqlite/query-dynamic.txx | 21 | ||||
-rw-r--r-- | odb/sqlite/query.cxx | 2 | ||||
-rw-r--r-- | odb/sqlite/query.hxx | 95 | ||||
-rw-r--r-- | odb/sqlite/query.ixx | 4 | ||||
-rw-r--r-- | odb/sqlite/traits.hxx | 12 |
9 files changed, 297 insertions, 34 deletions
diff --git a/odb/sqlite/makefile b/odb/sqlite/makefile index 30c55c7..b215461 100644 --- a/odb/sqlite/makefile +++ b/odb/sqlite/makefile @@ -12,6 +12,7 @@ error.cxx \ exceptions.cxx \ prepared-query.cxx \ query.cxx \ +query-dynamic.cxx \ query-const-expr.cxx \ simple-object-statements.cxx \ statement.cxx \ diff --git a/odb/sqlite/query-dynamic.cxx b/odb/sqlite/query-dynamic.cxx new file mode 100644 index 0000000..5f86b93 --- /dev/null +++ b/odb/sqlite/query-dynamic.cxx @@ -0,0 +1,136 @@ +// file : odb/sqlite/query-dynamic.cxx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include <cstddef> // std::size_t + +#include <odb/sqlite/query-dynamic.hxx> + +using namespace std; + +namespace odb +{ + namespace sqlite + { + static const char* logic_operators[] = {") AND (", ") OR ("}; + static const char* comp_operators[] = {"=", "!=", "<", ">", "<=", ">="}; + + static void + translate (query_base& q, const odb::query_base& s, size_t p) + { + typedef odb::query_base::clause_part part; + + const part& x (s.clause ()[p]); + + switch (x.kind) + { + case part::kind_column: + { + const query_column_base* c ( + static_cast<const query_column_base*> ( + x.native_info[id_sqlite].column)); + + q.append (c->table (), c->column ()); + break; + } + case part::kind_param_val: + case part::kind_param_ref: + { + const query_column_base* c ( + static_cast<const query_column_base*> ( + x.native_info[id_sqlite].column)); + + query_param_factory f ( + reinterpret_cast<query_param_factory> ( + x.native_info[id_sqlite].param_factory)); + + const odb::query_param* p ( + reinterpret_cast<const odb::query_param*> (x.data)); + + q.append (f (p->value, x.kind == part::kind_param_ref), + c->conversion ()); + break; + } + case part::kind_native: + { + q.append (s.strings ()[x.data]); + break; + } + case part::kind_true: + case part::kind_false: + { + q.append (x.kind == part::kind_true); + break; + } + case part::op_add: + { + translate (q, s, x.data); + translate (q, s, p - 1); + break; + } + case part::op_and: + case part::op_or: + { + q += "("; + translate (q, s, x.data); + q += logic_operators[x.kind - part::op_and]; + translate (q, s, p - 1); + q += ")"; + break; + } + case part::op_not: + { + q += "NOT ("; + translate (q, s, p - 1); + q += ")"; + break; + } + case part::op_null: + case part::op_not_null: + { + translate (q, s, p - 1); + q += (x.kind == part::op_null ? "IS NULL" : "IS NOT NULL"); + break; + } + case part::op_in: + { + size_t b (p - x.data); + + translate (q, s, b - 1); // column + q += "IN ("; + + for (size_t i (b); i != p; ++i) + { + if (i != b) + q += ","; + + translate (q, s, i); + } + + q += ")"; + break; + } + case part::op_eq: + case part::op_ne: + case part::op_lt: + case part::op_gt: + case part::op_le: + case part::op_ge: + { + translate (q, s, x.data); + q += comp_operators[x.kind - part::op_eq]; + translate (q, s, p - 1); + break; + } + } + } + + query_base:: + query_base (const odb::query_base& q) + : parameters_ (new (details::shared) query_params) + { + if (!q.empty ()) + translate (*this, q, q.clause ().size () - 1); + } + } +} diff --git a/odb/sqlite/query-dynamic.hxx b/odb/sqlite/query-dynamic.hxx new file mode 100644 index 0000000..aaad7f8 --- /dev/null +++ b/odb/sqlite/query-dynamic.hxx @@ -0,0 +1,33 @@ +// file : odb/sqlite/query-dynamic.hxx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_SQLITE_QUERY_DYNAMIC_HXX +#define ODB_SQLITE_QUERY_DYNAMIC_HXX + +#include <odb/pre.hxx> + +#include <odb/query.hxx> +#include <odb/query-dynamic.hxx> + +#include <odb/sqlite/query.hxx> + +namespace odb +{ + namespace sqlite + { + typedef details::shared_ptr<query_param> (*query_param_factory) ( + const void* val, bool by_ref); + + template <typename T, database_type_id ID> + details::shared_ptr<query_param> + query_param_factory_impl (const void*, bool); + } +} + +#include <odb/sqlite/query-dynamic.ixx> +#include <odb/sqlite/query-dynamic.txx> + +#include <odb/post.hxx> + +#endif // ODB_SQLITE_QUERY_DYNAMIC_HXX diff --git a/odb/sqlite/query-dynamic.ixx b/odb/sqlite/query-dynamic.ixx new file mode 100644 index 0000000..77f0f43 --- /dev/null +++ b/odb/sqlite/query-dynamic.ixx @@ -0,0 +1,27 @@ +// file : odb/sqlite/query-dynamic.ixx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +namespace odb +{ + namespace sqlite + { + // + // + template <typename T, database_type_id ID> + inline query_column<T, ID>:: + query_column (odb::query_column<T>& qc, + const char* table, const char* column, const char* conv) + : query_column_base (table, column, conv) + { + native_column_info& ci (qc.native_info[id_sqlite]); + ci.column = static_cast<query_column_base*> (this); + + // For some reason GCC needs this statically-typed pointer in + // order to instantiate the functions. + // + query_param_factory f (&query_param_factory_impl<T, ID>); + ci.param_factory = reinterpret_cast<void*> (f); + } + } +} diff --git a/odb/sqlite/query-dynamic.txx b/odb/sqlite/query-dynamic.txx new file mode 100644 index 0000000..c7d88cb --- /dev/null +++ b/odb/sqlite/query-dynamic.txx @@ -0,0 +1,21 @@ +// file : odb/sqlite/query-dynamic.txx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +namespace odb +{ + namespace sqlite + { + template <typename T, database_type_id ID> + details::shared_ptr<query_param> + query_param_factory_impl (const void* val, bool by_ref) + { + const T& v (*static_cast<const T*> (val)); + + return details::shared_ptr<query_param> ( + by_ref + ? new (details::shared) query_param_impl<T, ID> (ref_bind<T> (v)) + : new (details::shared) query_param_impl<T, ID> (val_bind<T> (v))); + } + } +} diff --git a/odb/sqlite/query.cxx b/odb/sqlite/query.cxx index 30e54f5..bce005f 100644 --- a/odb/sqlite/query.cxx +++ b/odb/sqlite/query.cxx @@ -180,7 +180,7 @@ namespace odb } void query_base:: - add (details::shared_ptr<query_param> p, const char* conv) + append (details::shared_ptr<query_param> p, const char* conv) { clause_.push_back (clause_part (clause_part::kind_param)); diff --git a/odb/sqlite/query.hxx b/odb/sqlite/query.hxx index 2a17b4f..18c10bb 100644 --- a/odb/sqlite/query.hxx +++ b/odb/sqlite/query.hxx @@ -11,6 +11,7 @@ #include <vector> #include <cstddef> // std::size_t +#include <odb/forward.hxx> // odb::query_column #include <odb/query.hxx> #include <odb/details/buffer.hxx> #include <odb/details/shared-ptr.hxx> @@ -149,7 +150,7 @@ namespace odb query_base (bool v) : parameters_ (new (details::shared) query_params) { - clause_.push_back (clause_part (v)); + append (v); } explicit @@ -193,6 +194,13 @@ namespace odb template <database_type_id ID> query_base (const query_column<bool, ID>&); + // Translate common query representation to SQLite native. Defined + // in query-dynamic.cxx + // + query_base (const odb::query_base&); + + // Copy c-tor and assignment. + // query_base (const query_base&); query_base& @@ -280,6 +288,8 @@ namespace odb return *this; } + // Implementation details. + // public: template <typename T, database_type_id ID> void @@ -290,14 +300,25 @@ namespace odb append (ref_bind<T>, const char* conv); void + append (details::shared_ptr<query_param>, const char* conv); + + void + append (bool v) + { + clause_.push_back (clause_part (v)); + } + + void append (const std::string& native); void - append (const char* table, const char* column); + append (const char* native) // Clashes with append(bool). + { + append (std::string (native)); + } - private: void - add (details::shared_ptr<query_param>, const char* conv); + append (const char* table, const char* column); private: typedef std::vector<clause_part> clause_type; @@ -417,28 +438,14 @@ namespace odb // query_column // - - template <typename T, typename T2> - class copy_bind: public val_bind<T> - { - public: - explicit - copy_bind (const T2& v): val_bind<T> (val), val (v) {} - - const T val; - }; - - template <typename T> - const T& - type_instance (); - - template <typename T, database_type_id ID> - struct query_column + struct LIBODB_SQLITE_EXPORT query_column_base { // Note that we keep shallow copies of the table, column, and conversion // expression. The latter can be NULL. // - query_column (const char* table, const char* column, const char* conv) + query_column_base (const char* table, + const char* column, + const char* conv) : table_ (table), column_ (column), conversion_ (conv) { } @@ -463,6 +470,40 @@ namespace odb return conversion_; } + protected: + const char* table_; + const char* column_; + const char* conversion_; + }; + + template <typename T, typename T2> + class copy_bind: public val_bind<T> + { + public: + explicit + copy_bind (const T2& v): val_bind<T> (val), val (v) {} + + const T val; + }; + + template <typename T> + const T& + type_instance (); + + template <typename T, database_type_id ID> + struct query_column: query_column_base + { + // Note that we keep shallow copies of the table, column, and conversion + // expression. The latter can be NULL. + // + query_column (const char* table, const char* column, const char* conv) + : query_column_base (table, column, conv) {} + + // Implementation is in query-dynamic.ixx. + // + query_column (odb::query_column<T>&, + const char* table, const char* column, const char* conv); + // is_null, is_not_null // public: @@ -1097,11 +1138,6 @@ namespace odb q.append (c.table (), c.column ()); return q; } - - private: - const char* table_; - const char* column_; - const char* conversion_; }; // Provide operator+() for using columns to construct native @@ -1353,6 +1389,11 @@ namespace odb : query_base (qc) { } + + query (const odb::query_base& q) + : query_base (q) + { + } }; } diff --git a/odb/sqlite/query.ixx b/odb/sqlite/query.ixx index c3a5f14..7413691 100644 --- a/odb/sqlite/query.ixx +++ b/odb/sqlite/query.ixx @@ -28,7 +28,7 @@ namespace odb inline void query_base:: append (val_bind<T> v, const char* conv) { - add ( + append ( details::shared_ptr<query_param> ( new (details::shared) query_param_impl<T, ID> (v)), conv); @@ -38,7 +38,7 @@ namespace odb inline void query_base:: append (ref_bind<T> r, const char* conv) { - add ( + append ( details::shared_ptr<query_param> ( new (details::shared) query_param_impl<T, ID> (r)), conv); diff --git a/odb/sqlite/traits.hxx b/odb/sqlite/traits.hxx index 20cd3f3..e6abf2d 100644 --- a/odb/sqlite/traits.hxx +++ b/odb/sqlite/traits.hxx @@ -293,7 +293,6 @@ namespace odb struct LIBODB_SQLITE_EXPORT c_string_value_traits { typedef const char* value_type; - typedef const char* query_type; typedef details::buffer image_type; static void @@ -307,16 +306,19 @@ namespace odb struct LIBODB_SQLITE_EXPORT default_value_traits<const char*, id_text>: c_string_value_traits { + typedef const char* query_type; }; template <std::size_t N> struct default_value_traits<char[N], id_text>: c_string_value_traits { + typedef char query_type[N]; }; template <std::size_t N> struct default_value_traits<const char[N], id_text>: c_string_value_traits { + typedef const char query_type[N]; }; #ifdef _WIN32 @@ -366,7 +368,6 @@ namespace odb struct LIBODB_SQLITE_EXPORT c_wstring_value_traits { typedef const wchar_t* value_type; - typedef const wchar_t* query_type; typedef details::buffer image_type; static void @@ -383,6 +384,7 @@ namespace odb struct LIBODB_SQLITE_EXPORT default_value_traits<const wchar_t*, id_text>: c_wstring_value_traits { + typedef const wchar_t* query_type; }; template <std::size_t N> @@ -392,6 +394,7 @@ namespace odb struct default_value_traits<wchar_t[N], id_text>: c_wstring_value_traits { + typedef wchar_t query_type[N]; }; template <std::size_t N> @@ -401,6 +404,7 @@ namespace odb struct default_value_traits<const wchar_t[N], id_text>: c_wstring_value_traits { + typedef const wchar_t query_type[N]; }; #endif // _WIN32 @@ -475,7 +479,7 @@ namespace odb { public: typedef char* value_type; - typedef const char* query_type; + typedef char query_type[N]; typedef details::buffer image_type; static void @@ -513,7 +517,7 @@ namespace odb { public: typedef unsigned char* value_type; - typedef const unsigned char* query_type; + typedef unsigned char query_type[N]; typedef details::buffer image_type; static void |