From 057c8299fb1fec24338404b28f2b33473e547bc8 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 24 Jan 2013 15:10:21 +0200 Subject: Add support for mapping char[N] to CHAR/VARCHAR database types Also improve query support for arrays (decaying). --- odb/mssql/mssql-types.hxx | 3 +- odb/mssql/query.hxx | 418 ++++++++++++++++++++++--------- odb/mssql/query.txx | 10 +- odb/mssql/traits.cxx | 100 +++++++- odb/mssql/traits.hxx | 626 +++++++++++++++++++++++++++++++++++++++------- odb/mssql/traits.txx | 262 +++++++++++++++++-- 6 files changed, 1171 insertions(+), 248 deletions(-) diff --git a/odb/mssql/mssql-types.hxx b/odb/mssql/mssql-types.hxx index 9ab7082..4166a21 100644 --- a/odb/mssql/mssql-types.hxx +++ b/odb/mssql/mssql-types.hxx @@ -53,8 +53,7 @@ namespace odb chunk_type, // The position of this chunk; chunk_first means // this is the first call, chunk_last means there // is no more data, chunk_null means this value is - // NULL, and chunk_one means the value is empty - // (in this case *total_size is 0). + // NULL, and chunk_one means the value is empty. std::size_t size_left, // Contains the amount of data left or 0 if this // information is not available. void* temp_buffer, // A temporary buffer that may be used by the diff --git a/odb/mssql/query.hxx b/odb/mssql/query.hxx index d9a84e4..3a82932 100644 --- a/odb/mssql/query.hxx +++ b/odb/mssql/query.hxx @@ -38,39 +38,96 @@ namespace odb // 0. As a result, for scale, the not specific special value will // be 0xFFFF (USHORT_MAX). // - template - class val_bind + struct val_bind { - public: + typedef const T& type; + explicit - val_bind (const T& v, unsigned short p = 0, unsigned short s = 0xFFFF) - : val (v), prec (p), scale (s) - { - } + val_bind (type v, unsigned short p = 0, unsigned short s = 0xFFFF) + : val (v), prec (p), scale (s) {} - const T& val; + type val; + + unsigned short prec; + unsigned short scale; + }; + + template + struct val_bind + { + typedef const T* type; + + explicit + val_bind (type v, unsigned short p = 0, unsigned short s = 0xFFFF) + : val (v), prec (p), scale (s) {} + + type val; unsigned short prec; unsigned short scale; }; template - class ref_bind + struct ref_bind { - public: + typedef const T& type; + explicit - ref_bind (const T& r, unsigned short p = 0, unsigned short s = 0xFFFF) - : ref (r) , prec (p), scale (s) - { - } + ref_bind (type r, unsigned short p = 0, unsigned short s = 0xFFFF) + : ref (r), prec (p), scale (s) {} + + const void* + ptr () const {return &ref;} + + type ref; + + unsigned short prec; + unsigned short scale; + }; - const T& ref; + template + struct ref_bind + { + typedef const T* type; + + explicit + ref_bind (type r, unsigned short p = 0, unsigned short s = 0xFFFF) + : ref (r), prec (p), scale (s) {} + + // Allow implicit conversion from decayed ref_bind's. + // + ref_bind (ref_bind r): ref (r.ref), prec (r.prec), scale (r.scale) {} + ref_bind (ref_bind r) + : ref (r.ref), prec (r.prec), scale (r.scale) {} + + const void* + ptr () const {return ref;} + + type ref; unsigned short prec; unsigned short scale; }; + template + struct val_bind_typed: val_bind + { + explicit + val_bind_typed (typename val_bind::type v, + unsigned short p = 0, + unsigned short s = 0xFFFF): val_bind (v, p, s) {} + }; + + template + struct ref_bind_typed: ref_bind + { + explicit + ref_bind_typed (typename ref_bind::type r, + unsigned short p = 0, + unsigned short s = 0xFFFF): ref_bind (r, p, s) {} + }; + struct LIBODB_MSSQL_EXPORT query_param: details::shared_base { typedef mssql::bind bind_type; @@ -166,8 +223,15 @@ namespace odb query_base (val_bind v) : binding_ (0, 0) { - append::db_type_id> ( - v, details::conversion::to ()); + *this += v; + } + + template + explicit + query_base (val_bind_typed v) + : binding_ (0, 0) + { + *this += v; } template @@ -175,8 +239,15 @@ namespace odb query_base (ref_bind r) : binding_ (0, 0) { - append::db_type_id> ( - r, details::conversion::to ()); + *this += r; + } + + template + explicit + query_base (ref_bind_typed r) + : binding_ (0, 0) + { + *this += r; } template @@ -237,6 +308,13 @@ namespace odb return val_bind (x, prec, scale); } + template + static val_bind_typed + _val (const T& x, unsigned short prec = 0, unsigned short scale = 0xFFFF) + { + return val_bind_typed (x, prec, scale); + } + template static ref_bind _ref (const T& x, unsigned short prec = 0, unsigned short scale = 0xFFFF) @@ -244,6 +322,13 @@ namespace odb return ref_bind (x, prec, scale); } + template + static ref_bind_typed + _ref (const T& x, unsigned short prec = 0, unsigned short scale = 0xFFFF) + { + return ref_bind_typed (x, prec, scale); + } + public: query_base& operator+= (const query_base&); @@ -264,6 +349,17 @@ namespace odb return *this; } + template + query_base& + operator+= (val_bind_typed v) + { + // We are not using default type_traits so no default conversion + // either. + // + append (v, 0); + return *this; + } + template query_base& operator+= (ref_bind r) @@ -273,6 +369,17 @@ namespace odb return *this; } + template + query_base& + operator+= (ref_bind_typed r) + { + // We are not using default type_traits so no default conversion + // either. + // + append (r, 0); + return *this; + } + // Implementation details. // public: @@ -334,16 +441,26 @@ namespace odb template inline query_base - operator+ (const query_base& q, ref_bind b) + operator+ (val_bind b, const query_base& q) + { + query_base r; + r += b; + r += q; + return r; + } + + template + inline query_base + operator+ (const query_base& q, val_bind_typed b) { query_base r (q); r += b; return r; } - template + template inline query_base - operator+ (val_bind b, const query_base& q) + operator+ (val_bind_typed b, const query_base& q) { query_base r; r += b; @@ -353,6 +470,15 @@ namespace odb template inline query_base + operator+ (const query_base& q, ref_bind b) + { + query_base r (q); + r += b; + return r; + } + + template + inline query_base operator+ (ref_bind b, const query_base& q) { query_base r; @@ -361,6 +487,25 @@ namespace odb return r; } + template + inline query_base + operator+ (const query_base& q, ref_bind_typed b) + { + query_base r (q); + r += b; + return r; + } + + template + inline query_base + operator+ (ref_bind_typed b, const query_base& q) + { + query_base r; + r += b; + r += q; + return r; + } + inline query_base operator+ (const query_base& q, const std::string& s) { @@ -388,16 +533,26 @@ namespace odb template inline query_base - operator+ (const std::string& s, ref_bind b) + operator+ (val_bind b, const std::string& s) + { + query_base r; + r += b; + r += s; + return r; + } + + template + inline query_base + operator+ (const std::string& s, val_bind_typed b) { query_base r (s); r += b; return r; } - template + template inline query_base - operator+ (val_bind b, const std::string& s) + operator+ (val_bind_typed b, const std::string& s) { query_base r; r += b; @@ -407,6 +562,15 @@ namespace odb template inline query_base + operator+ (const std::string& s, ref_bind b) + { + query_base r (s); + r += b; + return r; + } + + template + inline query_base operator+ (ref_bind b, const std::string& s) { query_base r; @@ -415,6 +579,25 @@ namespace odb return r; } + template + inline query_base + operator+ (const std::string& s, ref_bind_typed b) + { + query_base r (s); + r += b; + return r; + } + + template + inline query_base + operator+ (ref_bind_typed b, const std::string& s) + { + query_base r; + r += b; + r += s; + return r; + } + LIBODB_MSSQL_EXPORT query_base operator&& (const query_base& x, const query_base& y); @@ -482,23 +665,11 @@ namespace odb unsigned 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 { + typedef typename decay_traits::type decayed_type; + // Note that we keep shalow copies of the table, column, and conversion // expression. The latter can be NULL. // @@ -541,16 +712,17 @@ namespace odb // public: query_base - in (const T&, const T&) const; + in (decayed_type, decayed_type) const; query_base - in (const T&, const T&, const T&) const; + in (decayed_type, decayed_type, decayed_type) const; query_base - in (const T&, const T&, const T&, const T&) const; + in (decayed_type, decayed_type, decayed_type, decayed_type) const; query_base - in (const T&, const T&, const T&, const T&, const T&) const; + in (decayed_type, decayed_type, decayed_type, decayed_type, + decayed_type) const; template query_base @@ -560,7 +732,7 @@ namespace odb // public: query_base - equal (const T& v) const + equal (decayed_type v) const { return equal (val_bind (v)); } @@ -581,8 +753,7 @@ namespace odb query_base equal (val_bind v) const { - copy_bind c (v.val); - return equal (c); + return equal (val_bind (decayed_type (v.val)));; } query_base @@ -598,13 +769,13 @@ namespace odb } friend query_base - operator== (const query_column& c, const T& v) + operator== (const query_column& c, decayed_type v) { return c.equal (v); } friend query_base - operator== (const T& v, const query_column& c) + operator== (decayed_type v, const query_column& c) { return c.equal (v); } @@ -651,7 +822,7 @@ namespace odb // public: query_base - unequal (const T& v) const + unequal (decayed_type v) const { return unequal (val_bind (v)); } @@ -672,8 +843,7 @@ namespace odb query_base unequal (val_bind v) const { - copy_bind c (v.val); - return unequal (c); + return unequal (val_bind (decayed_type (v.val))); } query_base @@ -689,13 +859,13 @@ namespace odb } friend query_base - operator!= (const query_column& c, const T& v) + operator!= (const query_column& c, decayed_type v) { return c.unequal (v); } friend query_base - operator!= (const T& v, const query_column& c) + operator!= (decayed_type v, const query_column& c) { return c.unequal (v); } @@ -742,7 +912,7 @@ namespace odb // public: query_base - less (const T& v) const + less (decayed_type v) const { return less (val_bind (v)); } @@ -763,8 +933,7 @@ namespace odb query_base less (val_bind v) const { - copy_bind c (v.val); - return less (c); + return less (val_bind (decayed_type (v.val))); } query_base @@ -780,13 +949,13 @@ namespace odb } friend query_base - operator< (const query_column& c, const T& v) + operator< (const query_column& c, decayed_type v) { return c.less (v); } friend query_base - operator< (const T& v, const query_column& c) + operator< (decayed_type v, const query_column& c) { return c.greater (v); } @@ -833,7 +1002,7 @@ namespace odb // public: query_base - greater (const T& v) const + greater (decayed_type v) const { return greater (val_bind (v)); } @@ -854,8 +1023,7 @@ namespace odb query_base greater (val_bind v) const { - copy_bind c (v.val); - return greater (c); + return greater (val_bind (decayed_type (v.val))); } query_base @@ -871,13 +1039,13 @@ namespace odb } friend query_base - operator> (const query_column& c, const T& v) + operator> (const query_column& c, decayed_type v) { return c.greater (v); } friend query_base - operator> (const T& v, const query_column& c) + operator> (decayed_type v, const query_column& c) { return c.less (v); } @@ -924,7 +1092,7 @@ namespace odb // public: query_base - less_equal (const T& v) const + less_equal (decayed_type v) const { return less_equal (val_bind (v)); } @@ -945,8 +1113,7 @@ namespace odb query_base less_equal (val_bind v) const { - copy_bind c (v.val); - return less_equal (c); + return less_equal (val_bind (decayed_type (v.val))); } query_base @@ -962,13 +1129,13 @@ namespace odb } friend query_base - operator<= (const query_column& c, const T& v) + operator<= (const query_column& c, decayed_type v) { return c.less_equal (v); } friend query_base - operator<= (const T& v, const query_column& c) + operator<= (decayed_type v, const query_column& c) { return c.greater_equal (v); } @@ -1015,7 +1182,7 @@ namespace odb // public: query_base - greater_equal (const T& v) const + greater_equal (decayed_type v) const { return greater_equal (val_bind (v)); } @@ -1036,8 +1203,7 @@ namespace odb query_base greater_equal (val_bind v) const { - copy_bind c (v.val); - return greater_equal (c); + return greater_equal (val_bind (decayed_type (v.val))); } query_base @@ -1053,13 +1219,13 @@ namespace odb } friend query_base - operator>= (const query_column& c, const T& v) + operator>= (const query_column& c, decayed_type v) { return c.greater_equal (v); } friend query_base - operator>= (const T& v, const query_column& c) + operator>= (decayed_type v, const query_column& c) { return c.less_equal (v); } @@ -1111,7 +1277,8 @@ namespace odb { // We can compare columns only if we can compare their C++ types. // - (void) (sizeof (type_instance () == type_instance ())); + (void) (sizeof (decay_traits::instance () == + decay_traits::instance ())); query_base q (table_, column_); q += "="; @@ -1125,7 +1292,8 @@ namespace odb { // We can compare columns only if we can compare their C++ types. // - (void) (sizeof (type_instance () != type_instance ())); + (void) (sizeof (decay_traits::instance () != + decay_traits::instance ())); query_base q (table_, column_); q += "!="; @@ -1139,7 +1307,8 @@ namespace odb { // We can compare columns only if we can compare their C++ types. // - (void) (sizeof (type_instance () < type_instance ())); + (void) (sizeof (decay_traits::instance () < + decay_traits::instance ())); query_base q (table_, column_); q += "<"; @@ -1153,7 +1322,8 @@ namespace odb { // We can compare columns only if we can compare their C++ types. // - (void) (sizeof (type_instance () > type_instance ())); + (void) (sizeof (decay_traits::instance () > + decay_traits::instance ())); query_base q (table_, column_); q += ">"; @@ -1167,7 +1337,8 @@ namespace odb { // We can compare columns only if we can compare their C++ types. // - (void) (sizeof (type_instance () <= type_instance ())); + (void) (sizeof (decay_traits::instance () <= + decay_traits::instance ())); query_base q (table_, column_); q += "<="; @@ -1181,7 +1352,8 @@ namespace odb { // We can compare columns only if we can compare their C++ types. // - (void) (sizeof (type_instance () >= type_instance ())); + (void) (sizeof (decay_traits::instance () >= + decay_traits::instance ())); query_base q (table_, column_); q += ">="; @@ -1239,7 +1411,7 @@ namespace odb template struct query_param_impl: query_param { - query_param_impl (ref_bind r) : query_param (&r.ref) {} + query_param_impl (ref_bind r) : query_param (r.ptr ()) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} virtual bool @@ -1259,7 +1431,7 @@ namespace odb private: void - init (const T& v) + init (typename decay_traits::type v) { bool is_null (false); // Can't be NULL. value_traits::set_image (image_, is_null, v); @@ -1276,7 +1448,7 @@ namespace odb template struct query_param_impl: query_param { - query_param_impl (ref_bind r) : query_param (&r.ref) {} + query_param_impl (ref_bind r) : query_param (r.ptr ()) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} virtual bool @@ -1296,7 +1468,7 @@ namespace odb private: void - init (const T& v) + init (typename decay_traits::type v) { bool is_null (false); // Can't be NULL. value_traits::set_image (image_, is_null, v); @@ -1313,7 +1485,7 @@ namespace odb template struct query_param_impl: query_param { - query_param_impl (ref_bind r) : query_param (&r.ref) {} + query_param_impl (ref_bind r) : query_param (r.ptr ()) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} virtual bool @@ -1333,7 +1505,7 @@ namespace odb private: void - init (const T& v) + init (typename decay_traits::type v) { bool is_null (false); // Can't be NULL. value_traits::set_image (image_, is_null, v); @@ -1350,7 +1522,7 @@ namespace odb template struct query_param_impl: query_param { - query_param_impl (ref_bind r) : query_param (&r.ref) {} + query_param_impl (ref_bind r) : query_param (r.ptr ()) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} virtual bool @@ -1370,7 +1542,7 @@ namespace odb private: void - init (const T& v) + init (typename decay_traits::type v) { bool is_null (false); // Can't be NULL. value_traits::set_image (image_, is_null, v); @@ -1387,7 +1559,7 @@ namespace odb template struct query_param_impl: query_param { - query_param_impl (ref_bind r) : query_param (&r.ref) {} + query_param_impl (ref_bind r) : query_param (r.ptr ()) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} virtual bool @@ -1407,7 +1579,7 @@ namespace odb private: void - init (const T& v) + init (typename decay_traits::type v) { bool is_null (false); // Can't be NULL. value_traits::set_image (image_, is_null, v); @@ -1425,7 +1597,7 @@ namespace odb struct query_param_impl: query_param { query_param_impl (ref_bind r) - : query_param (&r.ref), + : query_param (r.ptr ()), prec_ (r.prec != 0 ? r.prec : 18), // Default is 18. scale_ (r.scale != 0xFFFF ? r.scale : 0) // Default is 0. { @@ -1459,7 +1631,7 @@ namespace odb private: void - init (const T& v) + init (typename decay_traits::type v) { bool is_null (false); // Can't be NULL. value_traits::set_image (image_, is_null, v); @@ -1479,7 +1651,7 @@ namespace odb template struct query_param_impl: query_param { - query_param_impl (ref_bind r) : query_param (&r.ref) {} + query_param_impl (ref_bind r) : query_param (r.ptr ()) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} virtual bool @@ -1499,7 +1671,7 @@ namespace odb private: void - init (const T& v) + init (typename decay_traits::type v) { bool is_null (false); // Can't be NULL. value_traits::set_image (image_, is_null, v); @@ -1516,7 +1688,7 @@ namespace odb template struct query_param_impl: query_param { - query_param_impl (ref_bind r) : query_param (&r.ref) {} + query_param_impl (ref_bind r) : query_param (r.ptr ()) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} virtual bool @@ -1536,7 +1708,7 @@ namespace odb private: void - init (const T& v) + init (typename decay_traits::type v) { bool is_null (false); // Can't be NULL. value_traits::set_image (image_, is_null, v); @@ -1554,7 +1726,7 @@ namespace odb struct query_param_impl: query_param { query_param_impl (ref_bind r) - : query_param (&r.ref), + : query_param (r.ptr ()), prec_ (r.prec != 0 ? r.prec : 24) { } @@ -1584,7 +1756,7 @@ namespace odb private: void - init (const T& v) + init (typename decay_traits::type v) { bool is_null (false); // Can't be NULL. value_traits::set_image (image_, is_null, v); @@ -1603,7 +1775,7 @@ namespace odb struct query_param_impl: query_param { query_param_impl (ref_bind r) - : query_param (&r.ref), + : query_param (r.ptr ()), prec_ (r.prec != 0 ? r.prec : 53) { } @@ -1633,7 +1805,7 @@ namespace odb private: void - init (const T& v) + init (typename decay_traits::type v) { bool is_null (false); // Can't be NULL. value_traits::set_image (image_, is_null, v); @@ -1652,7 +1824,7 @@ namespace odb struct query_param_impl: query_param { query_param_impl (ref_bind r) - : query_param (&r.ref), + : query_param (r.ptr ()), // Default to short data max (1024). buf_ (r.prec != 0 ? r.prec : 1024) { @@ -1686,7 +1858,7 @@ namespace odb private: void - init (const T& v) + init (typename decay_traits::type v) { bool is_null (false); // Can't be NULL. std::size_t size (0); @@ -1706,7 +1878,7 @@ namespace odb struct query_param_impl: query_param { query_param_impl (ref_bind r) - : query_param (&r.ref), + : query_param (r.ptr ()), // Precision is in 2-byte chars. Default to short data max (1024). buf_ (r.prec != 0 ? r.prec * 2 : 1024) { @@ -1740,7 +1912,7 @@ namespace odb private: void - init (const T& v) + init (typename decay_traits::type v) { bool is_null (false); // Can't be NULL. std::size_t size (0); @@ -1764,7 +1936,7 @@ namespace odb struct query_param_impl: query_param { query_param_impl (ref_bind r) - : query_param (&r.ref), + : query_param (r.ptr ()), // Default to short data max (1024). buf_ (r.prec != 0 ? r.prec : 1024) { @@ -1796,7 +1968,7 @@ namespace odb private: void - init (const T& v) + init (typename decay_traits::type v) { bool is_null (false); // Can't be NULL. std::size_t size (0); @@ -1838,7 +2010,7 @@ namespace odb long_query_param_impl { query_param_impl (ref_bind r) - : query_param (&r.ref), prec_ (r.prec) + : query_param (r.ptr ()), prec_ (r.prec) { } @@ -1889,7 +2061,7 @@ namespace odb private: void - init (const T& v) + init (typename decay_traits::type v) { bool is_null (false); // Can't be NULL. value_traits::set_image ( @@ -1911,7 +2083,7 @@ namespace odb long_query_param_impl { query_param_impl (ref_bind r) - : query_param (&r.ref), prec_ (r.prec) + : query_param (r.ptr ()), prec_ (r.prec) { } @@ -1962,7 +2134,7 @@ namespace odb private: void - init (const T& v) + init (typename decay_traits::type v) { bool is_null (false); // Can't be NULL. value_traits::set_image ( @@ -1984,7 +2156,7 @@ namespace odb long_query_param_impl { query_param_impl (ref_bind r) - : query_param (&r.ref), prec_ (r.prec) + : query_param (r.ptr ()), prec_ (r.prec) { } @@ -2033,7 +2205,7 @@ namespace odb private: void - init (const T& v) + init (typename decay_traits::type v) { bool is_null (false); // Can't be NULL. value_traits::set_image ( @@ -2053,7 +2225,7 @@ namespace odb template struct query_param_impl: query_param { - query_param_impl (ref_bind r) : query_param (&r.ref) {} + query_param_impl (ref_bind r) : query_param (r.ptr ()) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} virtual bool @@ -2073,7 +2245,7 @@ namespace odb private: void - init (const T& v) + init (typename decay_traits::type v) { bool is_null (false); // Can't be NULL. value_traits::set_image (image_, is_null, v); @@ -2091,7 +2263,7 @@ namespace odb struct query_param_impl: query_param { query_param_impl (ref_bind r) - : query_param (&r.ref), + : query_param (r.ptr ()), scale_ (r.scale != 0xFFFF ? r.scale : 7) // Default is 7. { } @@ -2121,7 +2293,7 @@ namespace odb private: void - init (const T& v) + init (typename decay_traits::type v) { bool is_null (false); // Can't be NULL. value_traits::set_image (image_, scale_, is_null, v); @@ -2140,7 +2312,7 @@ namespace odb struct query_param_impl: query_param { query_param_impl (ref_bind r) - : query_param (&r.ref), + : query_param (r.ptr ()), scale_ (r.scale != 0xFFFF ? r.scale : 7) // Default to datetime2/7. { } @@ -2170,7 +2342,7 @@ namespace odb private: void - init (const T& v) + init (typename decay_traits::type v) { bool is_null (false); // Can't be NULL. value_traits::set_image (image_, scale_, is_null, v); @@ -2189,7 +2361,7 @@ namespace odb struct query_param_impl: query_param { query_param_impl (ref_bind r) - : query_param (&r.ref), + : query_param (r.ptr ()), scale_ (r.scale != 0xFFFF ? r.scale : 7) // Default is 7. { } @@ -2219,7 +2391,7 @@ namespace odb private: void - init (const T& v) + init (typename decay_traits::type v) { bool is_null (false); // Can't be NULL. value_traits::set_image ( @@ -2238,7 +2410,7 @@ namespace odb template struct query_param_impl: query_param { - query_param_impl (ref_bind r) : query_param (&r.ref) {} + query_param_impl (ref_bind r) : query_param (r.ptr ()) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} virtual bool @@ -2258,7 +2430,7 @@ namespace odb private: void - init (const T& v) + init (typename decay_traits::type v) { bool is_null (false); // Can't be NULL. value_traits::set_image (image_, is_null, v); @@ -2275,7 +2447,7 @@ namespace odb template struct query_param_impl: query_param { - query_param_impl (ref_bind r) : query_param (&r.ref) {} + query_param_impl (ref_bind r) : query_param (r.ptr ()) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} virtual bool @@ -2295,7 +2467,7 @@ namespace odb private: void - init (const T& v) + init (typename decay_traits::type v) { bool is_null (false); // Can't be NULL. value_traits::set_image (image_, is_null, v); diff --git a/odb/mssql/query.txx b/odb/mssql/query.txx index d77ea83..fffbf87 100644 --- a/odb/mssql/query.txx +++ b/odb/mssql/query.txx @@ -27,7 +27,7 @@ namespace odb // template query_base query_column:: - in (const T& v1, const T& v2) const + in (decayed_type v1, decayed_type v2) const { query_base q (table_, column_); q += "IN ("; @@ -40,7 +40,7 @@ namespace odb template query_base query_column:: - in (const T& v1, const T& v2, const T& v3) const + in (decayed_type v1, decayed_type v2, decayed_type v3) const { query_base q (table_, column_); q += "IN ("; @@ -55,7 +55,8 @@ namespace odb template query_base query_column:: - in (const T& v1, const T& v2, const T& v3, const T& v4) const + in (decayed_type v1, decayed_type v2, decayed_type v3, + decayed_type v4) const { query_base q (table_, column_); q += "IN ("; @@ -72,7 +73,8 @@ namespace odb template query_base query_column:: - in (const T& v1, const T& v2, const T& v3, const T& v4, const T& v5) const + in (decayed_type v1, decayed_type v2, decayed_type v3, decayed_type v4, + decayed_type v5) const { query_base q (table_, column_); q += "IN ("; diff --git a/odb/mssql/traits.cxx b/odb/mssql/traits.cxx index 906473f..aba0433 100644 --- a/odb/mssql/traits.cxx +++ b/odb/mssql/traits.cxx @@ -13,9 +13,54 @@ namespace odb namespace mssql { // - // default_value_traits + // c_array_value_traits_base // + void c_array_value_traits_base:: + set_value (char* const& v, + const char* b, + size_t n, + bool is_null, + size_t N) + { + if (!is_null) + { + n = n < N ? n : N; + + if (n != 0) + memcpy (v, b, n); + } + else + n = 0; + if (n != N) // Append '\0' if there is space. + v[n] = '\0'; + } + + void c_array_value_traits_base:: + set_image (char* b, + size_t c, + size_t& n, + bool& is_null, + const char* v, + size_t N) + { + is_null = false; + + // Figure out the length. We cannot use strlen since it may + // not be 0-terminated (strnlen is not standard). + // + for (n = 0; n != N && v[n] != '\0'; ++n); + + if (n > c) + n = c; + + if (n != 0) + memcpy (b, v, n); + } + + // + // default_value_traits + // void default_value_traits:: param_callback (const void* context, size_t*, @@ -141,7 +186,6 @@ namespace odb // // c_long_string_value_traits // - void c_string_long_value_traits:: param_callback (const void* context, size_t*, @@ -157,9 +201,54 @@ namespace odb } // - // wstring_long_value_traits<2> + // c_warray_value_traits_base // + void c_warray_value_traits_base:: + set_value (wchar_t* const& v, + const ucs2_char* b, + size_t n, + bool is_null, + size_t N) + { + if (!is_null) + { + n = n < N ? n : N; + + if (n != 0) + functions::assign (v, b, n); + } + else + n = 0; + + if (n != N) // Append '\0' if there is space. + v[n] = L'\0'; + } + + void c_warray_value_traits_base:: + set_image (ucs2_char* b, + size_t c, + size_t& n, + bool& is_null, + const wchar_t* v, + size_t N) + { + is_null = false; + + // Figure out the length. We cannot use wcslen since it may + // not be 0-terminated (wcsnlen is not standard). + // + for (n = 0; n != N && v[n] != L'\0'; ++n); + + if (n > c) + n = c; + if (n != 0) + functions::assign (b, v, n); + } + + // + // wstring_long_value_traits<2> + // void wstring_long_value_traits<2>:: param_callback (const void* context, size_t*, @@ -234,7 +323,6 @@ namespace odb // // wstring_long_value_traits<4> // - #ifndef _WIN32 void wstring_long_value_traits<4>:: param_callback (const void* context, @@ -332,7 +420,6 @@ namespace odb // // c_wstring_long_value_traits<2> // - void c_wstring_long_value_traits<2>:: param_callback (const void* context, size_t*, @@ -350,7 +437,6 @@ namespace odb // // c_wstring_long_value_traits<4> // - #ifndef _WIN32 void c_wstring_long_value_traits<4>:: param_callback (const void* context, @@ -397,7 +483,6 @@ namespace odb // // default_value_traits, id_long_binary> // - void default_value_traits, id_long_binary>:: param_callback (const void* context, size_t*, @@ -466,7 +551,6 @@ namespace odb // // default_value_traits, id_long_binary> // - void default_value_traits, id_long_binary>:: param_callback (const void* context, size_t*, diff --git a/odb/mssql/traits.hxx b/odb/mssql/traits.hxx index a74b002..207a30a 100644 --- a/odb/mssql/traits.hxx +++ b/odb/mssql/traits.hxx @@ -602,7 +602,7 @@ namespace odb } }; - // const char* specialization for string. + // char*/const char* specialization for string. // // Specialization for const char* which only supports initialization // of an image from the value but not the other way around. This way @@ -633,23 +633,118 @@ namespace odb }; template <> + struct LIBODB_MSSQL_EXPORT default_value_traits: + c_string_value_traits {}; + + template <> struct LIBODB_MSSQL_EXPORT default_value_traits: - c_string_value_traits + c_string_value_traits {}; + + // char[N] specialization. + // + struct LIBODB_MSSQL_EXPORT c_array_value_traits_base { - typedef const char* query_type; + static void + set_value (char* const& v, + const char* b, + std::size_t n, + bool is_null, + std::size_t N); + + static void + set_image (char* b, + std::size_t c, + std::size_t& n, + bool& is_null, + const char* v, + std::size_t N); }; template - struct default_value_traits: c_string_value_traits + struct default_value_traits { + typedef char* value_type; typedef char query_type[N]; + typedef details::buffer image_type; + + static void + set_value (char* const& v, + const char* b, + std::size_t n, + bool is_null) + { + c_array_value_traits_base::set_value (v, b, n, is_null, N); + } + + static void + set_image (char* b, + std::size_t c, + std::size_t& n, + bool& is_null, + const char* v) + { + c_array_value_traits_base::set_image (b, c, n, is_null, v, N); + } }; + // std::array (string) specialization. + // +#ifdef ODB_CXX11 template - struct default_value_traits: - c_string_value_traits + struct default_value_traits, id_string> { - typedef const char query_type[N]; + typedef std::array value_type; + typedef std::array query_type; + typedef details::buffer image_type; + + static void + set_value (value_type& v, + const char* b, + std::size_t n, + bool is_null) + { + c_array_value_traits_base::set_value (v.data (), b, n, is_null, N); + } + + static void + set_image (char* b, + std::size_t c, + std::size_t& n, + bool& is_null, + const value_type& v) + { + c_array_value_traits_base::set_image (b, c, n, is_null, v.data (), N); + } + }; +#endif + + // char specialization. + // + template <> + struct LIBODB_MSSQL_EXPORT default_value_traits + { + typedef char value_type; + typedef char query_type; + typedef details::buffer image_type; + + static void + set_value (char& v, + const char* b, + std::size_t n, + bool is_null) + { + c_array_value_traits_base::set_value (&v, b, n, is_null, 1); + } + + static void + set_image (char* b, + std::size_t c, + std::size_t& n, + bool& is_null, + char v) + { + c_array_value_traits_base::set_image (b, c, n, is_null, &v, 1); + } }; // std::string specialization for long_string. @@ -702,7 +797,7 @@ namespace odb std::size_t tmp_capacity); }; - // const char* specialization for long_string. + // char*/const char* specialization for long_string. // class LIBODB_MSSQL_EXPORT c_string_long_value_traits { @@ -732,26 +827,112 @@ namespace odb }; template <> - struct LIBODB_MSSQL_EXPORT default_value_traits: - c_string_long_value_traits + struct LIBODB_MSSQL_EXPORT default_value_traits< + char*, id_long_string>: c_string_long_value_traits {}; + + template <> + struct LIBODB_MSSQL_EXPORT default_value_traits< + const char*, id_long_string>: c_string_long_value_traits {}; + + // char[N] specialization for long_string. + // + template + struct c_array_long_value_traits_base { - typedef const char* query_type; + static void + set_value (char* const& v, + result_callback_type& cb, + void*& context) + { + cb = &result_callback; + context = v; + } + + static void + set_image (param_callback_type& cb, + const void*& context, + bool& is_null, + const char* v) + { + is_null = false; + cb = ¶m_callback; + context = v; + } + + static void + param_callback (const void* context, + std::size_t* position, + const void** buffer, + std::size_t* size, + chunk_type* chunk, + void* tmp_buffer, + std::size_t tmp_capacity); + + static void + result_callback (void* context, + std::size_t* position, + void** buffer, + std::size_t* size, + chunk_type chunk, + std::size_t size_left, + void* tmp_buffer, + std::size_t tmp_capacity); }; template - struct default_value_traits: - c_string_long_value_traits + struct default_value_traits { + typedef char* value_type; typedef char query_type[N]; + typedef long_callback image_type; + + static void + set_value (char* const& v, + result_callback_type& cb, + void*& context) + { + c_array_long_value_traits_base::set_value (v, cb, context); + } + + static void + set_image (param_callback_type& cb, + const void*& context, + bool& is_null, + const char* v) + { + c_array_long_value_traits_base::set_image (cb, context, is_null, v); + } }; + // std::array (long_string) specialization. + // +#ifdef ODB_CXX11 template - struct default_value_traits: - c_string_long_value_traits + struct default_value_traits, id_long_string> { - typedef const char query_type[N]; + typedef std::array value_type; + typedef std::array query_type; + typedef long_callback image_type; + + static void + set_value (value_type& v, + result_callback_type& cb, + void*& context) + { + c_array_long_value_traits_base::set_value (v.data (), cb, context); + } + + static void + set_image (param_callback_type& cb, + const void*& context, + bool& is_null, + const value_type& v) + { + c_array_long_value_traits_base::set_image ( + cb, context, is_null, v.data ()); + } }; +#endif // std::wstring specialization for nstring. // @@ -770,6 +951,13 @@ namespace odb for (std::size_t i (0); i < n; ++i) b[i] = static_cast (s[i]); } + + static void + assign (wchar_t* s, const ucs2_char* b, std::size_t n) + { + for (std::size_t i (0); i < n; ++i) + s[i] = static_cast (b[i]); + } }; template <> @@ -784,9 +972,19 @@ namespace odb static void assign (ucs2_char* b, const wchar_t* s, std::size_t n) { - if (n != 0) - std::memcpy (b, s, n * sizeof (ucs2_char)); + std::memcpy (b, s, n * sizeof (ucs2_char)); } + + // On Windows ucs2_char is wchar_t which makes this function + // the same as the one above. + // +#ifndef _WIN32 + static void + assign (wchar_t* s, const ucs2_char* b, std::size_t n) + { + std::memcpy (s, b, n * sizeof (ucs2_char)); + } +#endif }; template <> @@ -823,11 +1021,12 @@ namespace odb if (n > c) n = c; - functions::assign (b, v.c_str (), n); + if (n != 0) + functions::assign (b, v.c_str (), n); } }; - // const wchar_t* specialization for nstring. + // wchar_t*/const wchar_t* specialization for nstring. // class LIBODB_MSSQL_EXPORT c_wstring_value_traits { @@ -850,30 +1049,126 @@ namespace odb if (n > c) n = c; - functions::assign (b, v, n); + if (n != 0) + functions::assign (b, v, n); } }; template <> - struct LIBODB_MSSQL_EXPORT default_value_traits: - c_wstring_value_traits + struct LIBODB_MSSQL_EXPORT default_value_traits: + c_wstring_value_traits {}; + + template <> + struct LIBODB_MSSQL_EXPORT default_value_traits< + const wchar_t*, id_nstring>: c_wstring_value_traits {}; + + // wchar_t[N] specialization. + // + struct LIBODB_MSSQL_EXPORT c_warray_value_traits_base { - typedef const wchar_t* query_type; + typedef wstring_functions<> functions; + + static void + set_value (wchar_t* const& v, + const ucs2_char* b, + std::size_t n, + bool is_null, + std::size_t N); + + static void + set_image (ucs2_char* b, + std::size_t c, + std::size_t& n, + bool& is_null, + const wchar_t* v, + std::size_t N); }; template - struct default_value_traits: - c_wstring_value_traits + struct default_value_traits { + typedef wchar_t* value_type; typedef wchar_t query_type[N]; + typedef details::buffer image_type; + + static void + set_value (wchar_t* const& v, + const ucs2_char* b, + std::size_t n, + bool is_null) + { + c_warray_value_traits_base::set_value (v, b, n, is_null, N); + } + + static void + set_image (ucs2_char* b, + std::size_t c, + std::size_t& n, + bool& is_null, + const wchar_t* v) + { + c_warray_value_traits_base::set_image (b, c, n, is_null, v, N); + } }; + // std::array (string) specialization. + // +#ifdef ODB_CXX11 template - struct default_value_traits: - c_wstring_value_traits + struct default_value_traits, id_nstring> + { + typedef std::array value_type; + typedef std::array query_type; + typedef details::buffer image_type; + + static void + set_value (value_type& v, + const ucs2_char* b, + std::size_t n, + bool is_null) + { + c_warray_value_traits_base::set_value (v.data (), b, n, is_null, N); + } + + static void + set_image (ucs2_char* b, + std::size_t c, + std::size_t& n, + bool& is_null, + const value_type& v) + { + c_warray_value_traits_base::set_image (b, c, n, is_null, v.data (), N); + } + }; +#endif + + // wchar_t specialization. + // + template <> + struct LIBODB_MSSQL_EXPORT default_value_traits { - typedef const wchar_t query_type[N]; + typedef wchar_t value_type; + typedef wchar_t query_type; + typedef details::buffer image_type; + + static void + set_value (wchar_t& v, + const ucs2_char* b, + std::size_t n, + bool is_null) + { + c_warray_value_traits_base::set_value (&v, b, n, is_null, 1); + } + + static void + set_image (ucs2_char* b, + std::size_t c, + std::size_t& n, + bool& is_null, + wchar_t v) + { + c_warray_value_traits_base::set_image (b, c, n, is_null, &v, 1); + } }; // std::wstring specialization for long_nstring. @@ -958,7 +1253,7 @@ namespace odb } }; - // const wchar_t* specialization for long_nstring. + // wchar_t*/const wchar_t* specialization for long_nstring. // template struct c_wstring_long_value_traits; @@ -1020,26 +1315,162 @@ namespace odb #endif template <> - struct LIBODB_MSSQL_EXPORT default_value_traits: - c_wstring_long_value_traits<> + struct LIBODB_MSSQL_EXPORT default_value_traits< + wchar_t*, id_long_nstring>: c_wstring_long_value_traits<> {}; + + template <> + struct LIBODB_MSSQL_EXPORT default_value_traits< + const wchar_t*, id_long_nstring>: c_wstring_long_value_traits<> {}; + + // char[N] specialization for long_nstring. + // + template + struct c_warray_long_value_traits_base; + + template + struct c_warray_long_value_traits_base { - typedef const wchar_t* query_type; + static void + set_value (wchar_t* const& v, + result_callback_type& cb, + void*& context) + { + cb = &result_callback; + context = v; + } + + static void + set_image (param_callback_type& cb, + const void*& context, + bool& is_null, + const wchar_t* v) + { + is_null = false; + cb = ¶m_callback; + context = v; + } + + static void + param_callback (const void* context, + std::size_t* position, + const void** buffer, + std::size_t* size, + chunk_type* chunk, + void* tmp_buffer, + std::size_t tmp_capacity); + + static void + result_callback (void* context, + std::size_t* position, + void** buffer, + std::size_t* size, + chunk_type chunk, + std::size_t size_left, + void* tmp_buffer, + std::size_t tmp_capacity); }; +#ifndef _WIN32 template - struct default_value_traits: - c_wstring_long_value_traits<> + struct c_warray_long_value_traits_base { + static void + set_value (wchar_t* const& v, + result_callback_type& cb, + void*& context) + { + cb = &result_callback; + context = v; + } + + static void + set_image (param_callback_type& cb, + const void*& context, + bool& is_null, + const wchar_t* v) + { + is_null = false; + cb = ¶m_callback; + context = v; + } + + static void + param_callback (const void* context, + std::size_t* position, + const void** buffer, + std::size_t* size, + chunk_type* chunk, + void* tmp_buffer, + std::size_t tmp_capacity); + + static void + result_callback (void* context, + std::size_t* position, + void** buffer, + std::size_t* size, + chunk_type chunk, + std::size_t size_left, + void* tmp_buffer, + std::size_t tmp_capacity); + }; +#endif + + template + struct default_value_traits + { + typedef wchar_t* value_type; typedef wchar_t query_type[N]; + typedef long_callback image_type; + + static void + set_value (wchar_t* const& v, + result_callback_type& cb, + void*& context) + { + c_warray_long_value_traits_base::set_value (v, cb, context); + } + + static void + set_image (param_callback_type& cb, + const void*& context, + bool& is_null, + const wchar_t* v) + { + c_warray_long_value_traits_base::set_image ( + cb, context, is_null, v); + } }; + // std::array (long_nstring) specialization. + // +#ifdef ODB_CXX11 template - struct default_value_traits: - c_wstring_long_value_traits<> + struct default_value_traits, id_long_nstring> { - typedef const wchar_t query_type[N]; + typedef std::array value_type; + typedef std::array query_type; + typedef long_callback image_type; + + static void + set_value (value_type& v, + result_callback_type& cb, + void*& context) + { + c_warray_long_value_traits_base::set_value ( + v.data (), cb, context); + } + + static void + set_image (param_callback_type& cb, + const void*& context, + bool& is_null, + const value_type& v) + { + c_warray_long_value_traits_base::set_image ( + cb, context, is_null, v.data ()); + } }; +#endif // std::vector (buffer) specialization for binary. // @@ -1289,10 +1720,6 @@ namespace odb template struct c_array_long_binary_value_traits { - typedef C* value_type; - typedef C query_type[N]; - typedef long_callback image_type; - static void set_value (C* const& v, result_callback_type& cb, @@ -1337,21 +1764,27 @@ namespace odb struct default_value_traits: c_array_long_binary_value_traits { + typedef char* value_type; + typedef char query_type[N]; + typedef long_callback image_type; }; template struct default_value_traits: c_array_long_binary_value_traits { + typedef unsigned char* value_type; + typedef unsigned char query_type[N]; + typedef long_callback image_type; }; #ifdef ODB_CXX11 // std::array (buffer) specialization for long_binary. // - template - struct array_long_binary_value_traits + template + struct default_value_traits, id_long_binary> { - typedef std::array value_type; + typedef std::array value_type; typedef value_type query_type; typedef long_callback image_type; @@ -1360,8 +1793,8 @@ namespace odb result_callback_type& cb, void*& context) { - cb = &result_callback; - context = v.data (); + c_array_long_binary_value_traits::set_value ( + v.data (), cb, context); } static void @@ -1370,41 +1803,36 @@ namespace odb bool& is_null, const value_type& v) { - is_null = false; - cb = ¶m_callback; - context = v.data (); + c_array_long_binary_value_traits::set_image ( + cb, context, is_null, v.data ()); } - - static void - param_callback (const void* context, - std::size_t* position, - const void** buffer, - std::size_t* size, - chunk_type* chunk, - void* tmp_buffer, - std::size_t tmp_capacity); - - static void - result_callback (void* context, - std::size_t* position, - void** buffer, - std::size_t* size, - chunk_type chunk, - std::size_t size_left, - void* tmp_buffer, - std::size_t tmp_capacity); }; template - struct default_value_traits, id_long_binary>: - array_long_binary_value_traits + struct default_value_traits, id_long_binary> { - }; + typedef std::array value_type; + typedef value_type query_type; + typedef long_callback image_type; - template - struct default_value_traits, id_long_binary>: - array_long_binary_value_traits - { + static void + set_value (value_type& v, + result_callback_type& cb, + void*& context) + { + c_array_long_binary_value_traits::set_value ( + v.data (), cb, context); + } + + static void + set_image (param_callback_type& cb, + const void*& context, + bool& is_null, + const value_type& v) + { + c_array_long_binary_value_traits::set_image ( + cb, context, is_null, v.data ()); + } }; #endif @@ -1616,6 +2044,12 @@ namespace odb }; template <> + struct default_type_traits + { + static const database_type_id db_type_id = id_long_string; + }; + + template <> struct default_type_traits { static const database_type_id db_type_id = id_long_string; @@ -1624,13 +2058,16 @@ namespace odb template struct default_type_traits { - static const database_type_id db_type_id = id_long_string; + // Use short string by default to minimize code bloat. Can + // always be overridden with _val()/_ref(). + // + static const database_type_id db_type_id = id_string; }; - template - struct default_type_traits + template <> + struct default_type_traits { - static const database_type_id db_type_id = id_long_string; + static const database_type_id db_type_id = id_string; }; // Wide string types. @@ -1642,6 +2079,12 @@ namespace odb }; template <> + struct default_type_traits + { + static const database_type_id db_type_id = id_long_nstring; + }; + + template <> struct default_type_traits { static const database_type_id db_type_id = id_long_nstring; @@ -1650,17 +2093,26 @@ namespace odb template struct default_type_traits { - static const database_type_id db_type_id = id_long_nstring; + // Use short string by default to minimize code bloat. Can + // always be overridden with _val()/_ref(). + // + static const database_type_id db_type_id = id_nstring; }; - template - struct default_type_traits + template <> + struct default_type_traits { - static const database_type_id db_type_id = id_long_nstring; + static const database_type_id db_type_id = id_nstring; }; // Binary types. // + template + struct default_type_traits + { + static const database_type_id db_type_id = id_long_binary; + }; + template <> struct default_type_traits > { diff --git a/odb/mssql/traits.txx b/odb/mssql/traits.txx index 634097e..1e2db27 100644 --- a/odb/mssql/traits.txx +++ b/odb/mssql/traits.txx @@ -11,7 +11,6 @@ namespace odb // // wrapped_value_traits // - template void wrapped_value_traits:: result_callback (void* context, @@ -52,11 +51,10 @@ namespace odb } // - // c_array_long_binary_value_traits + // c_array_long_value_traits_base // - - template - void c_array_long_binary_value_traits:: + template + void c_array_long_value_traits_base:: param_callback (const void* context, std::size_t*, const void** buffer, @@ -65,64 +63,281 @@ namespace odb void*, std::size_t) { + // Figure out the length. We cannot use strlen since it may + // not be 0-terminated (strnlen is not standard). + // + size_t n (0); + for (; n != N && static_cast (context)[n] != '\0'; ++n); + *buffer = context; - *size = N; + *size = n; *chunk = chunk_one; } - template - void c_array_long_binary_value_traits:: + template + void c_array_long_value_traits_base:: result_callback (void* context, - std::size_t*, + std::size_t* position, void** buffer, std::size_t* size, chunk_type chunk, - std::size_t size_left, + std::size_t, void* tmp_buf, std::size_t tmp_capacity) { - // The code is similar to the vector specialization. - // + char* p (static_cast (context)); + switch (chunk) { case chunk_null: case chunk_one: { - std::memset (context, 0, N); + *p = '\0'; break; } case chunk_first: { - assert (size_left != 0); + *buffer = p; + *size = N; + break; + } + case chunk_next: + { + // ODBC insists on appending '\0' to each chunk it returns. + // As a result, we can get here if the last character did not + // fit into our buffer. There could also be more data but since + // there is no way to stop until we read all the data, dump + // the remainder into the temporary buffer. + // + + // Use position to indicate whether this is the first "next + // chunk". + // + if (*position == 0) + *position = 1; + else if (*position == 1) + { + p[N - 1] = *static_cast (tmp_buf); + *position = 2; + } + + *buffer = tmp_buf; + *size = tmp_capacity; + break; + } + case chunk_last: + { + if (*position == 0) + { + if (*size < N) // Append '\0' if there is space. + p[*size] = '\0'; + } + else if (*position == 1) + p[N - 1] = *static_cast (tmp_buf); - *buffer = context; - *size = size_left < N ? size_left : N; + break; + } + } + } + + // + // c_warray_long_value_traits_base<2> + // + template + void c_warray_long_value_traits_base:: + param_callback (const void* context, + std::size_t*, + const void** buffer, + std::size_t* size, + chunk_type* chunk, + void*, + std::size_t) + { + // Figure out the length. We cannot use wcslen since it may + // not be 0-terminated (wcsnlen is not standard). + // + size_t n (0); + for (; n != N && static_cast (context)[n] != L'\0'; ++n); + + *buffer = context; + *size = n * 2; // In bytes. + *chunk = chunk_one; + } + + template + void c_warray_long_value_traits_base:: + result_callback (void* context, + std::size_t* position, + void** buffer, + std::size_t* size, + chunk_type chunk, + std::size_t, + void* tmp_buf, + std::size_t tmp_capacity) + { + wchar_t* p (static_cast (context)); + + switch (chunk) + { + case chunk_null: + case chunk_one: + { + *p = L'\0'; + break; + } + case chunk_first: + { + *buffer = p; + *size = N * 2; // In bytes break; } case chunk_next: { - // We can get here if total size is greater than N. There is - // no way to stop until we read all the data, so dump the - // remainder into the temporary buffer. + // ODBC insists on appending '\0' to each chunk it returns. + // As a result, we can get here if the last character did not + // fit into our buffer. There could also be more data but since + // there is no way to stop until we read all the data, dump + // the remainder into the temporary buffer. // + + // Use position to indicate whether this is the first "next + // chunk". + // + if (*position == 0) + *position = 1; + else if (*position == 1) + { + p[N - 1] = *static_cast (tmp_buf); + *position = 2; + } + *buffer = tmp_buf; *size = tmp_capacity; break; } case chunk_last: { + if (*position == 0) + { + size_t n (*size / 2); // In wide characters. + if (n < N) // Append '\0' if there is space. + p[n] = L'\0'; + } + else if (*position == 1) + p[N - 1] = *static_cast (tmp_buf); + break; } } } -#ifdef ODB_CXX11 +#ifndef _WIN32 // - // array_long_binary_value_traits + // c_warray_long_value_traits_base<4> // + template + void c_warray_long_value_traits_base:: + param_callback (const void* context, + std::size_t* pos, + const void** buffer, + std::size_t* size, + chunk_type* chunk, + void* tmp_buf, + std::size_t tmp_capacity) + { + // Here we cannot just return the pointer to the underlying buffer + // since the character sizes are different. Instead we copy the + // data to the temporary buffer. + // + ucs2_char* d (static_cast (tmp_buf)); + const wchar_t* s (static_cast (context) + *pos); + + size_t n (0); + tmp_capacity /= 2; // In UCS-2 character. + for (const wchar_t* e (s + N); + s != e && *s != L'\0' && n != tmp_capacity; + ++n, ++s) + d[n] = static_cast (*s); + + *buffer = d; + *size = n * 2; // In bytes. + *chunk = (n != tmp_capacity ? chunk_last : chunk_next); + if (*pos == 0) + { + if (*chunk == chunk_last) + *chunk = chunk_one; + else + *chunk = chunk_first; + } + + *pos += n; + } + + template + void c_warray_long_value_traits_base:: + result_callback (void* context, + std::size_t* pos, + void** buffer, + std::size_t* size, + chunk_type chunk, + std::size_t, + void* tmp_buf, + std::size_t tmp_capacity) + { + wchar_t* d (static_cast (context)); + const ucs2_char* s (static_cast (tmp_buf)); + + // Again, we cannot do direct buffer copy and have to use the + // temporary buffer instead. + // + switch (chunk) + { + case chunk_null: + case chunk_one: + { + *d = L'\0'; + break; + } + case chunk_first: + { + break; + } + case chunk_next: + case chunk_last: + { + // Append the data from the temporary buffer. + // + if (*pos < N) + { + *size /= 2; // In UCS-2 characters. + size_t n (N - *pos); + n = *size < n ? *size : n; + + wstring_functions<>::assign (d + *pos, s, n); + *pos += n; + + if (*pos < N) // Append '\0' if there is space. + d[*pos] = L'\0'; + } + + break; + } + } + + if (chunk == chunk_first || chunk == chunk_next) + { + *buffer = tmp_buf; + *size = tmp_capacity; + } + } +#endif + + // + // c_array_long_binary_value_traits + // template - void array_long_binary_value_traits:: + void c_array_long_binary_value_traits:: param_callback (const void* context, std::size_t*, const void** buffer, @@ -137,7 +352,7 @@ namespace odb } template - void array_long_binary_value_traits:: + void c_array_long_binary_value_traits:: result_callback (void* context, std::size_t*, void** buffer, @@ -181,6 +396,5 @@ namespace odb } } } -#endif } } -- cgit v1.1