From b3826d5ff054deeb7ba22aecb242cec2dca2f93a 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/oracle/exceptions.cxx | 10 +++ odb/oracle/exceptions.hxx | 6 ++ odb/oracle/makefile | 1 + odb/oracle/query-dynamic.cxx | 142 ++++++++++++++++++++++++++++++++++++++ odb/oracle/query-dynamic.hxx | 33 +++++++++ odb/oracle/query-dynamic.ixx | 73 ++++++++++++++++++++ odb/oracle/query-dynamic.txx | 26 +++++++ odb/oracle/query.cxx | 2 +- odb/oracle/query.hxx | 160 ++++++++++++++++++++++++++++--------------- odb/oracle/query.ixx | 4 +- odb/oracle/traits.hxx | 22 ++++-- 11 files changed, 413 insertions(+), 66 deletions(-) create mode 100644 odb/oracle/query-dynamic.cxx create mode 100644 odb/oracle/query-dynamic.hxx create mode 100644 odb/oracle/query-dynamic.ixx create mode 100644 odb/oracle/query-dynamic.txx diff --git a/odb/oracle/exceptions.cxx b/odb/oracle/exceptions.cxx index 87fc435..c8165cf 100644 --- a/odb/oracle/exceptions.cxx +++ b/odb/oracle/exceptions.cxx @@ -58,6 +58,16 @@ namespace odb } // + // lob_comparison + // + + const char* lob_comparison:: + what () const throw () + { + return "comparison of LOB values in queries not supported"; + } + + // // cli_exception // diff --git a/odb/oracle/exceptions.hxx b/odb/oracle/exceptions.hxx index e9f41e8..73fb4c5 100644 --- a/odb/oracle/exceptions.hxx +++ b/odb/oracle/exceptions.hxx @@ -83,6 +83,12 @@ namespace odb std::string what_; }; + struct LIBODB_ORACLE_EXPORT lob_comparison: odb::exception + { + virtual const char* + what () const throw (); + }; + struct LIBODB_ORACLE_EXPORT cli_exception: odb::exception { cli_exception (const std::string& what); diff --git a/odb/oracle/makefile b/odb/oracle/makefile index 34fda85..1d5c835 100644 --- a/odb/oracle/makefile +++ b/odb/oracle/makefile @@ -15,6 +15,7 @@ exceptions.cxx \ oracle-types.cxx \ prepared-query.cxx \ query.cxx \ +query-dynamic.cxx \ query-const-expr.cxx \ simple-object-statements.cxx \ statement.cxx \ diff --git a/odb/oracle/query-dynamic.cxx b/odb/oracle/query-dynamic.cxx new file mode 100644 index 0000000..5d8a2b7 --- /dev/null +++ b/odb/oracle/query-dynamic.cxx @@ -0,0 +1,142 @@ +// file : odb/oracle/query-dynamic.cxx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : ODB NCUEL; see accompanying LICENSE file + +#include // std::size_t + +#include +#include // lob_comparison + +using namespace std; + +namespace odb +{ + namespace oracle + { + 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 ( + x.native_info[id_oracle].column)); + + q.append (c->table (), c->column ()); + break; + } + case part::kind_param_val: + case part::kind_param_ref: + { + const query_column_base& qc ( + *static_cast ( + x.native_info[id_oracle].column)); + + query_param_factory f ( + reinterpret_cast ( + x.native_info[id_oracle].param_factory)); + + // If factory is NULL, then this is a LOB value. + // + if (f == 0) + throw lob_comparison (); + + const odb::query_param* p ( + reinterpret_cast (x.data)); + + q.append (f (p->value, qc, x.kind == part::kind_param_ref), + qc.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) + : binding_ (0, 0) + { + if (!q.empty ()) + translate (*this, q, q.clause ().size () - 1); + } + } +} diff --git a/odb/oracle/query-dynamic.hxx b/odb/oracle/query-dynamic.hxx new file mode 100644 index 0000000..e1b0229 --- /dev/null +++ b/odb/oracle/query-dynamic.hxx @@ -0,0 +1,33 @@ +// file : odb/oracle/query-dynamic.hxx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_ORACLE_QUERY_DYNAMIC_HXX +#define ODB_ORACLE_QUERY_DYNAMIC_HXX + +#include + +#include +#include + +#include + +namespace odb +{ + namespace oracle + { + typedef details::shared_ptr (*query_param_factory) ( + const void* val, const query_column_base&, bool by_ref); + + template + details::shared_ptr + query_param_factory_impl (const void*, const query_column_base&, bool); + } +} + +#include +#include + +#include + +#endif // ODB_ORACLE_QUERY_DYNAMIC_HXX diff --git a/odb/oracle/query-dynamic.ixx b/odb/oracle/query-dynamic.ixx new file mode 100644 index 0000000..4554921 --- /dev/null +++ b/odb/oracle/query-dynamic.ixx @@ -0,0 +1,73 @@ +// file : odb/oracle/query-dynamic.ixx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : ODB NCUEL; see accompanying LICENSE file + +namespace odb +{ + namespace oracle + { + // + // + template + inline query_column:: + query_column (odb::query_column& qc, + const char* table, + const char* column, + const char* conv, + unsigned short prec, + short scale) + : query_column_base (table, column, conv, prec, scale) + { + native_column_info& ci (qc.native_info[id_oracle]); + ci.column = static_cast (this); + + // For some reason GCC needs this statically-typed pointer in + // order to instantiate the functions. + // + query_param_factory f (&query_param_factory_impl); + ci.param_factory = reinterpret_cast (f); + } + + template + inline query_column:: + query_column (odb::query_column& qc, + const char* table, const char* column, const char*) + : lob_query_column (table, column) + { + native_column_info& ci (qc.native_info[id_oracle]); + ci.column = static_cast (this); + + // In Oracle LOBs cannot be compared. + // + ci.param_factory = 0; + } + + template + inline query_column:: + query_column (odb::query_column& qc, + const char* table, const char* column, const char*) + : lob_query_column (table, column) + { + native_column_info& ci (qc.native_info[id_oracle]); + ci.column = static_cast (this); + + // In Oracle LOBs cannot be compared. + // + ci.param_factory = 0; + } + + template + inline query_column:: + query_column (odb::query_column& qc, + const char* table, const char* column, const char*) + : lob_query_column (table, column) + { + native_column_info& ci (qc.native_info[id_oracle]); + ci.column = static_cast (this); + + // In Oracle LOBs cannot be compared. + // + ci.param_factory = 0; + } + } +} diff --git a/odb/oracle/query-dynamic.txx b/odb/oracle/query-dynamic.txx new file mode 100644 index 0000000..7daebc4 --- /dev/null +++ b/odb/oracle/query-dynamic.txx @@ -0,0 +1,26 @@ +// file : odb/oracle/query-dynamic.txx +// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC +// license : ODB NCUEL; see accompanying LICENSE file + +namespace odb +{ + namespace oracle + { + template + details::shared_ptr + query_param_factory_impl (const void* val, + const query_column_base& qc, + bool by_ref) + { + const T& v (*static_cast (val)); + + unsigned short p (qc.prec ()); + short s (qc.scale ()); + + return details::shared_ptr ( + by_ref + ? new (details::shared) query_param_impl (ref_bind (v, p, s)) + : new (details::shared) query_param_impl (val_bind (v, p, s))); + } + } +} diff --git a/odb/oracle/query.cxx b/odb/oracle/query.cxx index b6b3018..1121b9d 100644 --- a/odb/oracle/query.cxx +++ b/odb/oracle/query.cxx @@ -120,7 +120,7 @@ namespace odb } void query_base:: - add (details::shared_ptr p, const char* conv) + append (details::shared_ptr p, const char* conv) { clause_.push_back (clause_part (clause_part::kind_param)); diff --git a/odb/oracle/query.hxx b/odb/oracle/query.hxx index 9980833..1bf6853 100644 --- a/odb/oracle/query.hxx +++ b/odb/oracle/query.hxx @@ -11,6 +11,7 @@ #include #include // std::size_t +#include // odb::query_column #include #include @@ -136,7 +137,7 @@ namespace odb query_base (bool v) : binding_ (0, 0) { - clause_.push_back (clause_part (v)); + append (v); } explicit @@ -180,6 +181,13 @@ namespace odb template query_base (const query_column&); + // Translate common query representation to Oracle native. Defined + // in query-dynamic.cxx + // + query_base (const odb::query_base&); + + // Copy c-tor and assignment. + // query_base (const query_base&); query_base& @@ -264,24 +272,37 @@ namespace odb return *this; } + // Implementation details. + // public: template void - append (val_bind, const char* conv); + append (val_bind, const char* conv); template void - append (ref_bind, const char* conv); + append (ref_bind, const char* conv); + + void + append (details::shared_ptr, 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, const char* conv); + append (const char* table, const char* column); private: typedef std::vector clause_type; @@ -404,34 +425,18 @@ namespace odb // query_column // - - template - class copy_bind: public val_bind - { - public: - explicit - copy_bind (const T2& v): val_bind (val), val (v) {} - - const T val; - }; - - template - const T& - type_instance (); - - template - struct query_column + struct LIBODB_ORACLE_EXPORT query_column_base { - // Note that we keep shalow copies of the table, column, and conversion + // 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, - unsigned short prec = 0xFFF, - short scale = 0xFFF) - : table_ (table), column_ (column), conversion_ (conv), - prec_ (prec), scale_ (scale) + query_column_base (const char* table, + const char* column, + const char* conv, + unsigned short prec, + short scale) + : table_ (table), column_ (column), conversion_ (conv), + prec_ (prec), scale_ (scale) { } @@ -467,6 +472,51 @@ namespace odb return scale_; } + protected: + const char* table_; + const char* column_; + const char* conversion_; + + unsigned short prec_; + short scale_; + }; + + template + class copy_bind: public val_bind + { + public: + explicit + copy_bind (const T2& v): val_bind (val), val (v) {} + + const T val; + }; + + template + const T& + type_instance (); + + template + struct query_column: query_column_base + { + // Note that we keep shalow copies of the table, column, and conversion + // expression. The latter can be NULL. + // + query_column (const char* table, + const char* column, + const char* conv, + unsigned short prec = 0xFFF, + short scale = 0xFFF) + : query_column_base (table, column, conv, prec, scale) {} + + // Implementation is in query-dynamic.ixx. + // + query_column (odb::query_column&, + const char* table, + const char* column, + const char* conv, + unsigned short prec = 0xFFF, + short scale = 0xFFF); + // is_null, is_not_null // public: @@ -1137,14 +1187,6 @@ namespace odb q.append (c.table (), c.column ()); return q; } - - private: - const char* table_; - const char* column_; - const char* conversion_; - - unsigned short prec_; - short scale_; }; // @@ -1153,27 +1195,15 @@ namespace odb // predicates for these types. // - struct LIBODB_ORACLE_EXPORT lob_query_column + struct LIBODB_ORACLE_EXPORT lob_query_column: query_column_base { // Note that we keep shallow copies of the table and column names. // There is also no need for conversion expression since the only // valid tests are is IS NULL/IS NOT NULL. // lob_query_column (const char* table, const char* column) - : table_ (table), column_ (column) - { - } - - const char* - table () const + : query_column_base (table, column, 0, 0xFFF, 0xFFF) { - return table_; - } - - const char* - column () const - { - return column_; } // is_null, is_not_null @@ -1194,10 +1224,6 @@ namespace odb q += "IS NOT NULL"; return q; } - - private: - const char* table_; - const char* column_; }; template @@ -1207,6 +1233,11 @@ namespace odb : lob_query_column (table, column) { } + + // Implementation is in query-dynamic.ixx. + // + query_column (odb::query_column&, + const char* table, const char* column, const char*); }; template @@ -1216,6 +1247,11 @@ namespace odb : lob_query_column (table, column) { } + + // Implementation is in query-dynamic.ixx. + // + query_column (odb::query_column&, + const char* table, const char* column, const char*); }; template @@ -1225,6 +1261,11 @@ namespace odb : lob_query_column (table, column) { } + + // Implementation is in query-dynamic.ixx. + // + query_column (odb::query_column&, + const char* table, const char* column, const char*); }; // Provide operator+() for using columns to construct native @@ -1890,6 +1931,11 @@ namespace odb : query_base (qc) { } + + query (const odb::query_base& q) + : query_base (q) + { + } }; } diff --git a/odb/oracle/query.ixx b/odb/oracle/query.ixx index 611128c..224606f 100644 --- a/odb/oracle/query.ixx +++ b/odb/oracle/query.ixx @@ -16,7 +16,7 @@ namespace odb inline void query_base:: append (val_bind v, const char* conv) { - add ( + append ( details::shared_ptr ( new (details::shared) query_param_impl (v)), conv); @@ -26,7 +26,7 @@ namespace odb inline void query_base:: append (ref_bind r, const char* conv) { - add ( + append ( details::shared_ptr ( new (details::shared) query_param_impl (r)), conv); diff --git a/odb/oracle/traits.hxx b/odb/oracle/traits.hxx index 0f7c635..2cbce04 100644 --- a/odb/oracle/traits.hxx +++ b/odb/oracle/traits.hxx @@ -556,7 +556,6 @@ namespace odb { public: typedef const char* value_type; - typedef const char* query_type; typedef char* image_type; static void @@ -581,34 +580,40 @@ namespace odb struct LIBODB_ORACLE_EXPORT default_value_traits: c_string_value_traits { + typedef const char* query_type; }; template <> struct LIBODB_ORACLE_EXPORT default_value_traits: c_string_value_traits { + typedef const char* query_type; }; template struct default_value_traits: c_string_value_traits { + typedef char query_type[N]; }; template struct default_value_traits: c_string_value_traits { + typedef const char query_type[N]; }; template struct default_value_traits: c_string_value_traits { + typedef char query_type[N]; }; template struct default_value_traits: c_string_value_traits { + typedef const char query_type[N]; }; // std::vector (buffer) specialization for RAW. @@ -698,7 +703,7 @@ namespace odb struct default_value_traits { typedef char* value_type; - typedef const char* query_type; + typedef char query_type[N]; typedef char* image_type; static void @@ -729,7 +734,7 @@ namespace odb struct default_value_traits { typedef unsigned char* value_type; - typedef const unsigned char* query_type; + typedef unsigned char query_type[N]; typedef char* image_type; static void @@ -897,7 +902,6 @@ namespace odb { public: typedef const char* value_type; - typedef const char* query_type; typedef lob_callback image_type; static void @@ -925,36 +929,42 @@ namespace odb struct LIBODB_ORACLE_EXPORT default_value_traits: c_string_lob_value_traits { + typedef const char* query_type; }; template <> struct LIBODB_ORACLE_EXPORT default_value_traits: c_string_lob_value_traits { + typedef const char* query_type; }; template struct default_value_traits: c_string_lob_value_traits { + typedef char query_type[N]; }; template struct default_value_traits: c_string_lob_value_traits { + typedef const char query_type[N]; }; template struct default_value_traits: c_string_lob_value_traits { + typedef char query_type[N]; }; template struct default_value_traits: c_string_lob_value_traits { + typedef const char query_type[N]; }; // std::vector (buffer) specialization for BLOBs. @@ -1072,7 +1082,7 @@ namespace odb { public: typedef char* value_type; - typedef const char* query_type; + typedef char query_type[N]; typedef lob_callback image_type; static void @@ -1125,7 +1135,7 @@ namespace odb { public: typedef unsigned char* value_type; - typedef const unsigned char* query_type; + typedef unsigned char query_type[N]; typedef lob_callback image_type; static void -- cgit v1.1