aboutsummaryrefslogtreecommitdiff
path: root/odb/mssql/traits.txx
diff options
context:
space:
mode:
Diffstat (limited to 'odb/mssql/traits.txx')
-rw-r--r--odb/mssql/traits.txx262
1 files changed, 238 insertions, 24 deletions
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<W, ID, true>
//
-
template <typename W, database_type_id ID>
void wrapped_value_traits<W, ID, true>::
result_callback (void* context,
@@ -52,11 +51,10 @@ namespace odb
}
//
- // c_array_long_binary_value_traits
+ // c_array_long_value_traits_base
//
-
- template <typename C, std::size_t N>
- void c_array_long_binary_value_traits<C, N>::
+ template <std::size_t N>
+ void c_array_long_value_traits_base<N>::
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<const char*> (context)[n] != '\0'; ++n);
+
*buffer = context;
- *size = N;
+ *size = n;
*chunk = chunk_one;
}
- template <typename C, std::size_t N>
- void c_array_long_binary_value_traits<C, N>::
+ template <std::size_t N>
+ void c_array_long_value_traits_base<N>::
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<char> specialization.
- //
+ char* p (static_cast<char*> (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<const char*> (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<const char*> (tmp_buf);
- *buffer = context;
- *size = size_left < N ? size_left : N;
+ break;
+ }
+ }
+ }
+
+ //
+ // c_warray_long_value_traits_base<2>
+ //
+ template <std::size_t N>
+ void c_warray_long_value_traits_base<N, 2>::
+ 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<const wchar_t*> (context)[n] != L'\0'; ++n);
+
+ *buffer = context;
+ *size = n * 2; // In bytes.
+ *chunk = chunk_one;
+ }
+
+ template <std::size_t N>
+ void c_warray_long_value_traits_base<N, 2>::
+ 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<char*> (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<const wchar_t*> (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<const wchar_t*> (tmp_buf);
+
break;
}
}
}
-#ifdef ODB_CXX11
+#ifndef _WIN32
//
- // array_long_binary_value_traits
+ // c_warray_long_value_traits_base<4>
//
+ template <std::size_t N>
+ void c_warray_long_value_traits_base<N, 4>::
+ 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<ucs2_char*> (tmp_buf));
+ const wchar_t* s (static_cast<const wchar_t*> (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<ucs2_char> (*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 <std::size_t N>
+ void c_warray_long_value_traits_base<N, 4>::
+ 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<wchar_t*> (context));
+ const ucs2_char* s (static_cast<const ucs2_char*> (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 <typename C, std::size_t N>
- void array_long_binary_value_traits<C, N>::
+ void c_array_long_binary_value_traits<C, N>::
param_callback (const void* context,
std::size_t*,
const void** buffer,
@@ -137,7 +352,7 @@ namespace odb
}
template <typename C, std::size_t N>
- void array_long_binary_value_traits<C, N>::
+ void c_array_long_binary_value_traits<C, N>::
result_callback (void* context,
std::size_t*,
void** buffer,
@@ -181,6 +396,5 @@ namespace odb
}
}
}
-#endif
}
}