From a849d159fd03d3c954df3fc60826680f5d1afd65 Mon Sep 17 00:00:00 2001
From: Boris Kolpackov <boris@codesynthesis.com>
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/sqlite/query.hxx  | 324 +++++++++++++++++++++++++++++++++++++-------------
 odb/sqlite/query.txx  |  10 +-
 odb/sqlite/traits.cxx | 101 ++++++++++++++--
 odb/sqlite/traits.hxx | 255 ++++++++++++++++++++++++++++++++++-----
 4 files changed, 569 insertions(+), 121 deletions(-)

diff --git a/odb/sqlite/query.hxx b/odb/sqlite/query.hxx
index 0f7657c..5ee377f 100644
--- a/odb/sqlite/query.hxx
+++ b/odb/sqlite/query.hxx
@@ -30,23 +30,72 @@ namespace odb
   namespace sqlite
   {
     template <typename T>
-    class val_bind
+    struct val_bind
     {
-    public:
+      typedef const T& type;
+
+      explicit
+      val_bind (type v): val (v) {}
+
+      type val;
+    };
+
+    template <typename T, std::size_t N>
+    struct val_bind<T[N]>
+    {
+      typedef const T* type;
+
       explicit
-      val_bind (const T& v): val (v) {}
+      val_bind (type v): val (v) {}
 
-      const T& val;
+      type val;
     };
 
     template <typename T>
-    class ref_bind
+    struct ref_bind
+    {
+      typedef const T& type;
+
+      explicit
+      ref_bind (type r): ref (r) {}
+
+      const void*
+      ptr () const {return &ref;}
+
+      type ref;
+    };
+
+    template <typename T, std::size_t N>
+    struct ref_bind<T[N]>
+    {
+      typedef const T* type;
+
+      explicit
+      ref_bind (type r): ref (r) {}
+
+      // Allow implicit conversion from decayed ref_bind's.
+      //
+      ref_bind (ref_bind<T*> r): ref (r.ref) {}
+      ref_bind (ref_bind<const T*> r): ref (r.ref) {}
+
+      const void*
+      ptr () const {return ref;}
+
+      type ref;
+    };
+
+    template <typename T, database_type_id ID>
+    struct val_bind_typed: val_bind<T>
     {
-    public:
       explicit
-      ref_bind (const T& r): ref (r) {}
+      val_bind_typed (typename val_bind<T>::type v): val_bind<T> (v) {}
+    };
 
-      const T& ref;
+    template <typename T, database_type_id ID>
+    struct ref_bind_typed: ref_bind<T>
+    {
+      explicit
+      ref_bind_typed (typename ref_bind<T>::type r): ref_bind<T> (r) {}
     };
 
     struct LIBODB_SQLITE_EXPORT query_param: details::shared_base
@@ -178,8 +227,15 @@ namespace odb
       query_base (val_bind<T> v)
         : parameters_ (new (details::shared) query_params)
       {
-        append<T, type_traits<T>::db_type_id> (
-          v, details::conversion<T>::to ());
+        *this += v;
+      }
+
+      template <typename T, database_type_id ID>
+      explicit
+      query_base (val_bind_typed<T, ID> v)
+        : parameters_ (new (details::shared) query_params)
+      {
+        *this += v;
       }
 
       template <typename T>
@@ -187,8 +243,15 @@ namespace odb
       query_base (ref_bind<T> r)
         : parameters_ (new (details::shared) query_params)
       {
-        append<T, type_traits<T>::db_type_id> (
-          r, details::conversion<T>::to ());
+        *this += r;
+      }
+
+      template <typename T, database_type_id ID>
+      explicit
+      query_base (ref_bind_typed<T, ID> r)
+        : parameters_ (new (details::shared) query_params)
+      {
+        *this += r;
       }
 
       template <database_type_id ID>
@@ -252,6 +315,13 @@ namespace odb
         return val_bind<T> (x);
       }
 
+      template <database_type_id ID, typename T>
+      static val_bind_typed<T, ID>
+      _val (const T& x)
+      {
+        return val_bind_typed<T, ID> (x);
+      }
+
       template <typename T>
       static ref_bind<T>
       _ref (const T& x)
@@ -259,6 +329,13 @@ namespace odb
         return ref_bind<T> (x);
       }
 
+      template <database_type_id ID, typename T>
+      static ref_bind_typed<T, ID>
+      _ref (const T& x)
+      {
+        return ref_bind_typed<T, ID> (x);
+      }
+
     public:
       query_base&
       operator+= (const query_base&);
@@ -279,6 +356,17 @@ namespace odb
         return *this;
       }
 
+      template <typename T, database_type_id ID>
+      query_base&
+      operator+= (val_bind_typed<T, ID> v)
+      {
+        // We are not using default type_traits so no default conversion
+        // either.
+        //
+        append<T, ID> (v, 0);
+        return *this;
+      }
+
       template <typename T>
       query_base&
       operator+= (ref_bind<T> r)
@@ -288,6 +376,17 @@ namespace odb
         return *this;
       }
 
+      template <typename T, database_type_id ID>
+      query_base&
+      operator+= (ref_bind_typed<T, ID> r)
+      {
+        // We are not using default type_traits so no default conversion
+        // either.
+        //
+        append<T, ID> (r, 0);
+        return *this;
+      }
+
       // Implementation details.
       //
     public:
@@ -346,16 +445,26 @@ namespace odb
 
     template <typename T>
     inline query_base
-    operator+ (const query_base& q, ref_bind<T> b)
+    operator+ (val_bind<T> b, const query_base& q)
+    {
+      query_base r;
+      r += b;
+      r += q;
+      return r;
+    }
+
+    template <typename T, database_type_id ID>
+    inline query_base
+    operator+ (const query_base& q, val_bind_typed<T, ID> b)
     {
       query_base r (q);
       r += b;
       return r;
     }
 
-    template <typename T>
+    template <typename T, database_type_id ID>
     inline query_base
-    operator+ (val_bind<T> b, const query_base& q)
+    operator+ (val_bind_typed<T, ID> b, const query_base& q)
     {
       query_base r;
       r += b;
@@ -365,6 +474,15 @@ namespace odb
 
     template <typename T>
     inline query_base
+    operator+ (const query_base& q, ref_bind<T> b)
+    {
+      query_base r (q);
+      r += b;
+      return r;
+    }
+
+    template <typename T>
+    inline query_base
     operator+ (ref_bind<T> b, const query_base& q)
     {
       query_base r;
@@ -373,6 +491,25 @@ namespace odb
       return r;
     }
 
+    template <typename T, database_type_id ID>
+    inline query_base
+    operator+ (const query_base& q, ref_bind_typed<T, ID> b)
+    {
+      query_base r (q);
+      r += b;
+      return r;
+    }
+
+    template <typename T, database_type_id ID>
+    inline query_base
+    operator+ (ref_bind_typed<T, ID> 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)
     {
@@ -400,16 +537,26 @@ namespace odb
 
     template <typename T>
     inline query_base
-    operator+ (const std::string& s, ref_bind<T> b)
+    operator+ (val_bind<T> b, const std::string& s)
+    {
+      query_base r;
+      r += b;
+      r += s;
+      return r;
+    }
+
+    template <typename T, database_type_id ID>
+    inline query_base
+    operator+ (const std::string& s, val_bind_typed<T, ID> b)
     {
       query_base r (s);
       r += b;
       return r;
     }
 
-    template <typename T>
+    template <typename T, database_type_id ID>
     inline query_base
-    operator+ (val_bind<T> b, const std::string& s)
+    operator+ (val_bind_typed<T, ID> b, const std::string& s)
     {
       query_base r;
       r += b;
@@ -419,6 +566,15 @@ namespace odb
 
     template <typename T>
     inline query_base
+    operator+ (const std::string& s, ref_bind<T> b)
+    {
+      query_base r (s);
+      r += b;
+      return r;
+    }
+
+    template <typename T>
+    inline query_base
     operator+ (ref_bind<T> b, const std::string& s)
     {
       query_base r;
@@ -427,6 +583,25 @@ namespace odb
       return r;
     }
 
+    template <typename T, database_type_id ID>
+    inline query_base
+    operator+ (const std::string& s, ref_bind_typed<T, ID> b)
+    {
+      query_base r (s);
+      r += b;
+      return r;
+    }
+
+    template <typename T, database_type_id ID>
+    inline query_base
+    operator+ (ref_bind_typed<T, ID> b, const std::string& s)
+    {
+      query_base r;
+      r += b;
+      r += s;
+      return r;
+    }
+
     LIBODB_SQLITE_EXPORT query_base
     operator&& (const query_base&, const query_base&);
 
@@ -476,23 +651,11 @@ namespace odb
       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
     {
+      typedef typename decay_traits<T>::type decayed_type;
+
       // Note that we keep shallow copies of the table, column, and conversion
       // expression. The latter can be NULL.
       //
@@ -527,16 +690,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 <typename I>
       query_base
@@ -546,7 +710,7 @@ namespace odb
       //
     public:
       query_base
-      equal (const T& v) const
+      equal (decayed_type v) const
       {
         return equal (val_bind<T> (v));
       }
@@ -564,8 +728,7 @@ namespace odb
       query_base
       equal (val_bind<T2> v) const
       {
-        copy_bind<T, T2> c (v.val);
-        return equal (c);
+        return equal (val_bind<T> (decayed_type (v.val)));
       }
 
       query_base
@@ -578,13 +741,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);
       }
@@ -631,7 +794,7 @@ namespace odb
       //
     public:
       query_base
-      unequal (const T& v) const
+      unequal (decayed_type v) const
       {
         return unequal (val_bind<T> (v));
       }
@@ -649,8 +812,7 @@ namespace odb
       query_base
       unequal (val_bind<T2> v) const
       {
-        copy_bind<T, T2> c (v.val);
-        return unequal (c);
+        return unequal (val_bind<T> (decayed_type (v.val)));
       }
 
       query_base
@@ -663,13 +825,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);
       }
@@ -716,7 +878,7 @@ namespace odb
       //
     public:
       query_base
-      less (const T& v) const
+      less (decayed_type v) const
       {
         return less (val_bind<T> (v));
       }
@@ -734,8 +896,7 @@ namespace odb
       query_base
       less (val_bind<T2> v) const
       {
-        copy_bind<T, T2> c (v.val);
-        return less (c);
+        return less (val_bind<T> (decayed_type (v.val)));
       }
 
       query_base
@@ -748,13 +909,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);
       }
@@ -801,7 +962,7 @@ namespace odb
       //
     public:
       query_base
-      greater (const T& v) const
+      greater (decayed_type v) const
       {
         return greater (val_bind<T> (v));
       }
@@ -819,8 +980,7 @@ namespace odb
       query_base
       greater (val_bind<T2> v) const
       {
-        copy_bind<T, T2> c (v.val);
-        return greater (c);
+        return greater (val_bind<T> (decayed_type (v.val)));
       }
 
       query_base
@@ -833,13 +993,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);
       }
@@ -886,7 +1046,7 @@ namespace odb
       //
     public:
       query_base
-      less_equal (const T& v) const
+      less_equal (decayed_type v) const
       {
         return less_equal (val_bind<T> (v));
       }
@@ -904,8 +1064,7 @@ namespace odb
       query_base
       less_equal (val_bind<T2> v) const
       {
-        copy_bind<T, T2> c (v.val);
-        return less_equal (c);
+        return less_equal (val_bind<T> (decayed_type (v.val)));
       }
 
       query_base
@@ -918,13 +1077,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);
       }
@@ -971,7 +1130,7 @@ namespace odb
       //
     public:
       query_base
-      greater_equal (const T& v) const
+      greater_equal (decayed_type v) const
       {
         return greater_equal (val_bind<T> (v));
       }
@@ -989,8 +1148,7 @@ namespace odb
       query_base
       greater_equal (val_bind<T2> v) const
       {
-        copy_bind<T, T2> c (v.val);
-        return greater_equal (c);
+        return greater_equal (val_bind<T> (decayed_type (v.val)));
       }
 
       query_base
@@ -1003,13 +1161,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);
       }
@@ -1061,7 +1219,8 @@ namespace odb
       {
         // We can compare columns only if we can compare their C++ types.
         //
-        (void) (sizeof (type_instance<T> () == type_instance<T2> ()));
+        (void) (sizeof (decay_traits<T>::instance () ==
+                        decay_traits<T2>::instance ()));
 
         query_base q (table_, column_);
         q += "=";
@@ -1075,7 +1234,8 @@ namespace odb
       {
         // We can compare columns only if we can compare their C++ types.
         //
-        (void) (sizeof (type_instance<T> () != type_instance<T2> ()));
+        (void) (sizeof (decay_traits<T>::instance () !=
+                        decay_traits<T2>::instance ()));
 
         query_base q (table_, column_);
         q += "!=";
@@ -1089,7 +1249,8 @@ namespace odb
       {
         // We can compare columns only if we can compare their C++ types.
         //
-        (void) (sizeof (type_instance<T> () < type_instance<T2> ()));
+        (void) (sizeof (decay_traits<T>::instance () <
+                        decay_traits<T2>::instance ()));
 
         query_base q (table_, column_);
         q += "<";
@@ -1103,7 +1264,8 @@ namespace odb
       {
         // We can compare columns only if we can compare their C++ types.
         //
-        (void) (sizeof (type_instance<T> () > type_instance<T2> ()));
+        (void) (sizeof (decay_traits<T>::instance () >
+                        decay_traits<T2>::instance ()));
 
         query_base q (table_, column_);
         q += ">";
@@ -1117,7 +1279,8 @@ namespace odb
       {
         // We can compare columns only if we can compare their C++ types.
         //
-        (void) (sizeof (type_instance<T> () <= type_instance<T2> ()));
+        (void) (sizeof (decay_traits<T>::instance () <=
+                        decay_traits<T2>::instance ()));
 
         query_base q (table_, column_);
         q += "<=";
@@ -1131,7 +1294,8 @@ namespace odb
       {
         // We can compare columns only if we can compare their C++ types.
         //
-        (void) (sizeof (type_instance<T> () >= type_instance<T2> ()));
+        (void) (sizeof (decay_traits<T>::instance () >=
+                        decay_traits<T2>::instance ()));
 
         query_base q (table_, column_);
         q += ">=";
@@ -1189,7 +1353,7 @@ namespace odb
     template <typename T>
     struct query_param_impl<T, id_integer>: query_param
     {
-      query_param_impl (ref_bind<T> r) : query_param (&r.ref) {}
+      query_param_impl (ref_bind<T> r) : query_param (r.ptr ()) {}
       query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);}
 
       virtual bool
@@ -1208,7 +1372,7 @@ namespace odb
 
     private:
       void
-      init (const T& v)
+      init (typename decay_traits<T>::type v)
       {
         bool is_null (false); // Can't be NULL.
         value_traits<T, id_integer>::set_image (image_, is_null, v);
@@ -1223,7 +1387,7 @@ namespace odb
     template <typename T>
     struct query_param_impl<T, id_real>: query_param
     {
-      query_param_impl (ref_bind<T> r) : query_param (&r.ref) {}
+      query_param_impl (ref_bind<T> r) : query_param (r.ptr ()) {}
       query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);}
 
       virtual bool
@@ -1242,7 +1406,7 @@ namespace odb
 
     private:
       void
-      init (const T& v)
+      init (typename decay_traits<T>::type v)
       {
         bool is_null (false); // Can't be NULL.
         value_traits<T, id_real>::set_image (image_, is_null, v);
@@ -1257,7 +1421,7 @@ namespace odb
     template <typename T>
     struct query_param_impl<T, id_text>: query_param
     {
-      query_param_impl (ref_bind<T> r) : query_param (&r.ref) {}
+      query_param_impl (ref_bind<T> r) : query_param (r.ptr ()) {}
       query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);}
 
       virtual bool
@@ -1276,7 +1440,7 @@ namespace odb
 
     private:
       bool
-      init (const T& v)
+      init (typename decay_traits<T>::type v)
       {
         bool is_null (false); // Can't be NULL.
         std::size_t cap (buffer_.capacity ());
@@ -1294,7 +1458,7 @@ namespace odb
     template <typename T>
     struct query_param_impl<T, id_blob>: query_param
     {
-      query_param_impl (ref_bind<T> r) : query_param (&r.ref) {}
+      query_param_impl (ref_bind<T> r) : query_param (r.ptr ()) {}
       query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);}
 
       virtual bool
@@ -1313,7 +1477,7 @@ namespace odb
 
     private:
       bool
-      init (const T& v)
+      init (typename decay_traits<T>::type v)
       {
         bool is_null (false); // Can't be NULL.
         std::size_t cap (buffer_.capacity ());
diff --git a/odb/sqlite/query.txx b/odb/sqlite/query.txx
index f719ece..7342187 100644
--- a/odb/sqlite/query.txx
+++ b/odb/sqlite/query.txx
@@ -26,7 +26,7 @@ namespace odb
     //
     template <typename T, database_type_id ID>
     query_base query_column<T, ID>::
-    in (const T& v1, const T& v2) const
+    in (decayed_type v1, decayed_type v2) const
     {
       query_base q (table_, column_);
       q += "IN (";
@@ -39,7 +39,7 @@ namespace odb
 
     template <typename T, database_type_id ID>
     query_base query_column<T, ID>::
-    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 (";
@@ -54,7 +54,8 @@ namespace odb
 
     template <typename T, database_type_id ID>
     query_base query_column<T, ID>::
-    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 (";
@@ -71,7 +72,8 @@ namespace odb
 
     template <typename T, database_type_id ID>
     query_base query_column<T, ID>::
-    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/sqlite/traits.cxx b/odb/sqlite/traits.cxx
index 3f9c5cb..753c181 100644
--- a/odb/sqlite/traits.cxx
+++ b/odb/sqlite/traits.cxx
@@ -15,7 +15,6 @@ namespace odb
     //
     // default_value_traits<std::string>
     //
-
     void default_value_traits<string, id_text>::
     set_image (buffer& b, size_t& n, bool& is_null, const string& v)
     {
@@ -32,7 +31,6 @@ namespace odb
     //
     // c_string_value_traits
     //
-
     void c_string_value_traits::
     set_image (buffer& b, size_t& n, bool& is_null, const char* v)
     {
@@ -46,11 +44,55 @@ namespace odb
         memcpy (b.data (), v, n);
     }
 
-#ifdef _WIN32
     //
-    // default_value_traits<std::wstring>
+    // c_array_value_traits_base
     //
+    void c_array_value_traits_base::
+    set_value (char* const& v,
+               const details::buffer& b,
+               size_t n,
+               bool is_null,
+               size_t N)
+    {
+      if (!is_null)
+      {
+        n = n < N ? n : N;
+
+        if (n != 0)
+          memcpy (v, b.data (), n);
+      }
+      else
+        n = 0;
+
+      if (n != N) // Append '\0' if there is space.
+        v[n] = '\0';
+    }
 
+    void c_array_value_traits_base::
+    set_image (details::buffer& b,
+               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 > b.capacity ())
+        b.capacity (n);
+
+      if (n != 0)
+        memcpy (b.data (), v, n);
+    }
+
+    //
+    // default_value_traits<std::wstring>
+    //
+#ifdef _WIN32
     void default_value_traits<wstring, id_text>::
     set_image (buffer& b, size_t& n, bool& is_null, const wstring& v)
     {
@@ -67,7 +109,6 @@ namespace odb
     //
     // c_wstring_value_traits
     //
-
     void c_wstring_value_traits::
     set_image (buffer& b, size_t& n, bool& is_null, const wchar_t* v)
     {
@@ -80,12 +121,59 @@ namespace odb
       if (n != 0)
         memcpy (b.data (), v, n);
     }
+
+    //
+    // c_warray_value_traits_base
+    //
+    void c_warray_value_traits_base::
+    set_value (wchar_t* const& v,
+               const details::buffer& b,
+               size_t n,
+               bool is_null,
+               size_t N)
+    {
+      if (!is_null)
+      {
+        n /= 2;
+        n = n < N ? n : N;
+
+        if (n != 0)
+          memcpy (v, b.data (), n * sizeof (wchar_t));
+      }
+      else
+        n = 0;
+
+      if (n != N) // Append '\0' if there is space.
+        v[n] = L'\0';
+    }
+
+    void c_warray_value_traits_base::
+    set_image (details::buffer& b,
+               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);
+
+      n *= 2;
+
+      if (n > b.capacity ())
+        b.capacity (n);
+
+      if (n != 0)
+        memcpy (b.data (), v, n);
+    }
 #endif // _WIN32
 
     //
     // default_value_traits<vector<char>, id_blob>
     //
-
     void default_value_traits<vector<char>, id_blob>::
     set_image (details::buffer& b,
                size_t& n,
@@ -107,7 +195,6 @@ namespace odb
     //
     // default_value_traits<vector<unsigned char>, id_blob>
     //
-
     void default_value_traits<vector<unsigned char>, id_blob>::
     set_image (details::buffer& b,
                size_t& n,
diff --git a/odb/sqlite/traits.hxx b/odb/sqlite/traits.hxx
index e6abf2d..0cdf171 100644
--- a/odb/sqlite/traits.hxx
+++ b/odb/sqlite/traits.hxx
@@ -284,7 +284,7 @@ namespace odb
                  const std::string&);
     };
 
-    // const char* specialization
+    // char*/const char* specialization
     //
     // Specialization for const char* which only supports initialization
     // of an image from the value but not the other way around. This way
@@ -303,35 +303,129 @@ namespace odb
     };
 
     template <>
+    struct LIBODB_SQLITE_EXPORT default_value_traits<char*, id_text>:
+      c_string_value_traits {};
+
+    template <>
     struct LIBODB_SQLITE_EXPORT default_value_traits<const char*, id_text>:
-      c_string_value_traits
+      c_string_value_traits {};
+
+    // char[N] specialization.
+    //
+    struct LIBODB_SQLITE_EXPORT c_array_value_traits_base
     {
-      typedef const char* query_type;
+      static void
+      set_value (char* const& v,
+                 const details::buffer& b,
+                 std::size_t n,
+                 bool is_null,
+                 std::size_t N);
+
+      static void
+      set_image (details::buffer& b,
+                 std::size_t& n,
+                 bool& is_null,
+                 const char* v,
+                 std::size_t N);
     };
 
     template <std::size_t N>
-    struct default_value_traits<char[N], id_text>: c_string_value_traits
+    struct default_value_traits<char[N], id_text>
     {
+      typedef char* value_type;
       typedef char query_type[N];
+      typedef details::buffer image_type;
+
+      static void
+      set_value (char* const& v,
+                 const details::buffer& 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 (details::buffer& b,
+                 std::size_t& n,
+                 bool& is_null,
+                 const char* v)
+      {
+        c_array_value_traits_base::set_image (b, n, is_null, v, N);
+      }
     };
 
+    // std::array<char, N> (string) specialization.
+    //
+#ifdef ODB_CXX11
     template <std::size_t N>
-    struct default_value_traits<const char[N], id_text>: c_string_value_traits
+    struct default_value_traits<std::array<char, N>, id_text>
     {
-      typedef const char query_type[N];
+      typedef std::array<char, N> value_type;
+      typedef std::array<char, N> query_type;
+      typedef details::buffer image_type;
+
+      static void
+      set_value (value_type& v,
+                 const details::buffer& 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 (details::buffer& b,
+                 std::size_t& n,
+                 bool& is_null,
+                 const value_type& v)
+      {
+        c_array_value_traits_base::set_image (b, n, is_null, v.data (), N);
+      }
+    };
+#endif
+
+    // char specialization.
+    //
+    template <>
+    struct LIBODB_SQLITE_EXPORT default_value_traits<char, id_text>
+    {
+      typedef char value_type;
+      typedef char query_type;
+      typedef details::buffer image_type;
+
+      static void
+      set_value (char& v,
+                 const details::buffer& 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 (details::buffer& b,
+                 std::size_t& n,
+                 bool& is_null,
+                 char v)
+      {
+        c_array_value_traits_base::set_image (b, n, is_null, &v, 1);
+      }
     };
 
 #ifdef _WIN32
     // std::wstring specialization. Using UTF-16 binding.
     //
-    template <>
-    struct image_traits<std::wstring, id_text>
+    struct wstring_image_traits
     {
       typedef details::buffer image_type;
       static const bind::buffer_type bind_value = bind::text16;
     };
 
     template <>
+    struct image_traits<std::wstring, id_text>: wstring_image_traits {};
+
+    template <>
     struct LIBODB_SQLITE_EXPORT default_value_traits<std::wstring, id_text>
     {
       typedef std::wstring value_type;
@@ -357,14 +451,8 @@ namespace odb
                  const std::wstring&);
     };
 
-    // const wchar_t* specialization
+    // wchar_t*/const wchar_t* specialization.
     //
-    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;
@@ -378,33 +466,130 @@ namespace odb
     };
 
     template <>
-    struct image_traits<const wchar_t*, id_text>: c_wstring_image_traits {};
+    struct image_traits<wchar_t*, id_text>: wstring_image_traits {};
+
+    template <>
+    struct LIBODB_SQLITE_EXPORT default_value_traits<wchar_t*, id_text>:
+      c_wstring_value_traits {};
+
+    template <>
+    struct image_traits<const wchar_t*, id_text>: wstring_image_traits {};
 
     template <>
     struct LIBODB_SQLITE_EXPORT default_value_traits<const wchar_t*, id_text>:
-      c_wstring_value_traits
+      c_wstring_value_traits {};
+
+    // wchar_t[N] specialization.
+    //
+    struct LIBODB_SQLITE_EXPORT c_warray_value_traits_base
     {
-      typedef const wchar_t* query_type;
+      static void
+      set_value (wchar_t* const& v,
+                 const details::buffer& b,
+                 std::size_t n,
+                 bool is_null,
+                 std::size_t N);
+
+      static void
+      set_image (details::buffer& b,
+                 std::size_t& n,
+                 bool& is_null,
+                 const wchar_t* v,
+                 std::size_t N);
     };
 
     template <std::size_t N>
-    struct image_traits<wchar_t[N], id_text>: c_wstring_image_traits {};
+    struct image_traits<wchar_t[N], id_text>: wstring_image_traits {};
 
     template <std::size_t N>
-    struct default_value_traits<wchar_t[N], id_text>:
-      c_wstring_value_traits
+    struct default_value_traits<wchar_t[N], id_text>
     {
+      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 details::buffer& 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 (details::buffer& b,
+                 std::size_t& n,
+                 bool& is_null,
+                 const wchar_t* v)
+      {
+        c_warray_value_traits_base::set_image (b, n, is_null, v, N);
+      }
     };
 
+    // std::array<wchar_t, N> (string) specialization.
+    //
+#ifdef ODB_CXX11
     template <std::size_t N>
-    struct image_traits<const wchar_t[N], id_text>: c_wstring_image_traits {};
+    struct image_traits<std::array<wchar_t, N>, id_text>:
+      wstring_image_traits {};
 
     template <std::size_t N>
-    struct default_value_traits<const wchar_t[N], id_text>:
-      c_wstring_value_traits
+    struct default_value_traits<std::array<wchar_t, N>, id_text>
+    {
+      typedef std::array<wchar_t, N> value_type;
+      typedef std::array<wchar_t, N> query_type;
+      typedef details::buffer image_type;
+
+      static void
+      set_value (value_type& v,
+                 const details::buffer& 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 (details::buffer& b,
+                 std::size_t& n,
+                 bool& is_null,
+                 const value_type& v)
+      {
+        c_warray_value_traits_base::set_image (b, n, is_null, v.data (), N);
+      }
+    };
+#endif
+
+    // wchar_t specialization.
+    //
+    template <>
+    struct image_traits<wchar_t, id_text>: wstring_image_traits {};
+
+    template <>
+    struct LIBODB_SQLITE_EXPORT default_value_traits<wchar_t, id_text>
     {
-      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 details::buffer& 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 (details::buffer& b,
+                 std::size_t& n,
+                 bool& is_null,
+                 wchar_t v)
+      {
+        c_warray_value_traits_base::set_image (b, n, is_null, &v, 1);
+      }
     };
 #endif // _WIN32
 
@@ -634,9 +819,7 @@ namespace odb
     struct default_type_traits;
 
     template <typename T>
-    class type_traits: public default_type_traits<T>
-    {
-    };
+    class type_traits: public default_type_traits<T> {};
 
     // Integral types.
     //
@@ -729,6 +912,12 @@ namespace odb
     };
 
     template <>
+    struct default_type_traits<char*>
+    {
+      static const database_type_id db_type_id = id_text;
+    };
+
+    template <>
     struct default_type_traits<const char*>
     {
       static const database_type_id db_type_id = id_text;
@@ -740,14 +929,20 @@ namespace odb
       static const database_type_id db_type_id = id_text;
     };
 
-    template <std::size_t N>
-    struct default_type_traits<const char[N]>
+    template <>
+    struct default_type_traits<char>
     {
       static const database_type_id db_type_id = id_text;
     };
 
     // Binary types.
     //
+    template <std::size_t N>
+    struct default_type_traits<unsigned char[N]>
+    {
+      static const database_type_id db_type_id = id_blob;
+    };
+
     template <>
     struct default_type_traits<std::vector<char> >
     {
-- 
cgit v1.1