From 866f0ce4fa567db60d46741a5c865cdf2741c619 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 10 Sep 2012 12:12:06 +0200 Subject: Add support for alternative UTF-16 image for TEXT in SQLite Use it to handle QString and support std::wstring on Windows. --- odb/sqlite/query.hxx | 2 +- odb/sqlite/sqlite-types.hxx | 3 +- odb/sqlite/statement.cxx | 34 ++++++++++--- odb/sqlite/traits.cxx | 36 ++++++++++++++ odb/sqlite/traits.hxx | 118 +++++++++++++++++++++++++++++++++++++++----- 5 files changed, 172 insertions(+), 21 deletions(-) diff --git a/odb/sqlite/query.hxx b/odb/sqlite/query.hxx index 1e8a0a0..5991c51 100644 --- a/odb/sqlite/query.hxx +++ b/odb/sqlite/query.hxx @@ -1225,7 +1225,7 @@ namespace odb virtual void bind (sqlite::bind* b) { - b->type = sqlite::bind::text; + b->type = image_traits::bind_value; b->buffer = buffer_.data (); b->size = &size_; } diff --git a/odb/sqlite/sqlite-types.hxx b/odb/sqlite/sqlite-types.hxx index 316c032..295cd1f 100644 --- a/odb/sqlite/sqlite-types.hxx +++ b/odb/sqlite/sqlite-types.hxx @@ -22,7 +22,8 @@ namespace odb { integer, // Buffer is long long; size, capacity, truncated are unused. real, // Buffer is double; size, capacity, truncated are unused. - text, // Buffer is a char array. + text, // Buffer is a UTF-8 char array. + text16, // Buffer is a UTF-16 2-byte char array (sizes in bytes). blob // Buffer is a char array. }; diff --git a/odb/sqlite/statement.cxx b/odb/sqlite/statement.cxx index 60cf410..36066ff 100644 --- a/odb/sqlite/statement.cxx +++ b/odb/sqlite/statement.cxx @@ -125,6 +125,15 @@ namespace odb SQLITE_STATIC); break; } + case bind::text16: + { + e = sqlite3_bind_text16 (stmt_, + j, + b.buffer, + static_cast (*b.size), + SQLITE_STATIC); + break; + } case bind::blob: { e = sqlite3_bind_blob (stmt_, @@ -189,17 +198,28 @@ namespace odb break; } case bind::text: + case bind::text16: case bind::blob: { - // SQLite documentation recommends that we first call *_text() - // or *_blob() function in order to force the type conversion, - // if any. + // SQLite documentation recommends that we first call *_text(), + // *_text16(), or *_blob() function in order to force the type + // conversion, if any. // - const void* d (b.type == bind::text - ? sqlite3_column_text (stmt_, j) - : sqlite3_column_blob (stmt_, j)); + const void* d; - *b.size = static_cast (sqlite3_column_bytes (stmt_, j)); + if (b.type != bind::text16) + { + d = b.type == bind::text + ? sqlite3_column_text (stmt_, j) + : sqlite3_column_blob (stmt_, j); + *b.size = static_cast (sqlite3_column_bytes (stmt_, j)); + } + else + { + d = sqlite3_column_text16 (stmt_, j); + *b.size = static_cast ( + sqlite3_column_bytes16 (stmt_, j)); + } if (*b.size > b.capacity) { diff --git a/odb/sqlite/traits.cxx b/odb/sqlite/traits.cxx index 0e875a2..3f9c5cb 100644 --- a/odb/sqlite/traits.cxx +++ b/odb/sqlite/traits.cxx @@ -46,6 +46,42 @@ namespace odb memcpy (b.data (), v, n); } +#ifdef _WIN32 + // + // default_value_traits + // + + void default_value_traits:: + set_image (buffer& b, size_t& n, bool& is_null, const wstring& v) + { + is_null = false; + n = v.size () * 2; + + if (n > b.capacity ()) + b.capacity (n); + + if (n != 0) + memcpy (b.data (), v.c_str (), n); + } + + // + // c_wstring_value_traits + // + + void c_wstring_value_traits:: + set_image (buffer& b, size_t& n, bool& is_null, const wchar_t* v) + { + is_null = false; + n = wcslen (v) * 2; + + if (n > b.capacity ()) + b.capacity (n); + + if (n != 0) + memcpy (b.data (), v, n); + } +#endif // _WIN32 + // // default_value_traits, id_blob> // diff --git a/odb/sqlite/traits.hxx b/odb/sqlite/traits.hxx index 65883b6..0de67f9 100644 --- a/odb/sqlite/traits.hxx +++ b/odb/sqlite/traits.hxx @@ -20,6 +20,7 @@ #include #include +#include #include namespace odb @@ -38,20 +39,27 @@ namespace odb // image_traits // - template + template struct image_traits; - template <> - struct image_traits {typedef long long image_type;}; + template + struct image_traits {typedef long long image_type;}; - template <> - struct image_traits {typedef double image_type;}; + template + struct image_traits {typedef double image_type;}; - template <> - struct image_traits {typedef details::buffer image_type;}; + template + struct image_traits + { + typedef details::buffer image_type; - template <> - struct image_traits {typedef details::buffer image_type;}; + // By default the text is in UTF-8. + // + static const bind::buffer_type bind_value = bind::text; + }; + + template + struct image_traits {typedef details::buffer image_type;}; // // value_traits @@ -97,7 +105,7 @@ namespace odb typedef W value_type; typedef wrapped_type query_type; - typedef typename image_traits::image_type image_type; + typedef typename image_traits::image_type image_type; typedef value_traits vtraits; @@ -136,7 +144,7 @@ namespace odb typedef W value_type; typedef wrapped_type query_type; - typedef typename image_traits::image_type image_type; + typedef typename image_traits::image_type image_type; typedef value_traits vtraits; @@ -184,7 +192,7 @@ namespace odb { typedef T value_type; typedef T query_type; - typedef typename image_traits::image_type image_type; + typedef typename image_traits::image_type image_type; static void set_value (T& v, const image_type& i, bool is_null) @@ -305,6 +313,92 @@ namespace odb { }; +#ifdef _WIN32 + // std::wstring specialization. Using UTF-16 binding. + // + template <> + struct image_traits + { + typedef details::buffer image_type; + static const bind::buffer_type bind_value = bind::text16; + }; + + template <> + struct LIBODB_SQLITE_EXPORT default_value_traits + { + typedef std::wstring value_type; + typedef std::wstring query_type; + typedef details::buffer image_type; + + static void + set_value (std::wstring& v, + const details::buffer& b, + std::size_t n, + bool is_null) + { + if (!is_null) + v.assign (reinterpret_cast (b.data ()), n / 2); + else + v.erase (); + } + + static void + set_image (details::buffer&, + std::size_t& n, + bool& is_null, + const std::wstring&); + }; + + // const wchar_t* specialization + // + template <> + struct c_wstring_image_traits + { + typedef details::buffer image_type; + static const bind::buffer_type bind_value = bind::text16; + }; + + 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 + set_image (details::buffer&, + std::size_t& n, + bool& is_null, + const wchar_t*); + }; + + template <> + struct image_traits: c_wstring_image_traits {}; + + template <> + struct LIBODB_SQLITE_EXPORT default_value_traits: + c_wstring_value_traits + { + }; + + template + struct image_traits: c_wstring_image_traits {}; + + template + struct default_value_traits: + c_wstring_value_traits + { + }; + + template + struct image_traits: c_wstring_image_traits {}; + + template + struct default_value_traits: + c_wstring_value_traits + { + }; +#endif // _WIN32 + // std::vector (buffer) specialization. // template <> -- cgit v1.1