diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2011-12-13 09:52:44 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2011-12-13 09:52:44 +0200 |
commit | 213740c161499a5961fa426d1b77c7d68763c5df (patch) | |
tree | c728215544c5bb32c2b5e6d2e627b04db74a2843 | |
parent | de057163bce41b64926f6d777ce1b09a98d9bb6e (diff) |
Initial value traits implementations
-rw-r--r-- | odb/mssql/makefile | 1 | ||||
-rw-r--r-- | odb/mssql/mssql-fwd.hxx | 60 | ||||
-rw-r--r-- | odb/mssql/mssql-types.hxx | 11 | ||||
-rw-r--r-- | odb/mssql/statement.cxx | 74 | ||||
-rw-r--r-- | odb/mssql/traits.cxx | 15 | ||||
-rw-r--r-- | odb/mssql/traits.hxx | 498 | ||||
-rw-r--r-- | odb/mssql/traits.txx | 11 |
7 files changed, 661 insertions, 9 deletions
diff --git a/odb/mssql/makefile b/odb/mssql/makefile index acdeb76..6e054d5 100644 --- a/odb/mssql/makefile +++ b/odb/mssql/makefile @@ -17,6 +17,7 @@ object-statements.cxx \ statement.cxx \ statements-base.cxx \ tracer.cxx \ +traits.cxx \ transaction.cxx \ transaction-impl.cxx diff --git a/odb/mssql/mssql-fwd.hxx b/odb/mssql/mssql-fwd.hxx index 3579403..20acab3 100644 --- a/odb/mssql/mssql-fwd.hxx +++ b/odb/mssql/mssql-fwd.hxx @@ -93,6 +93,66 @@ typedef SQLHANDLE SQLHDESC; # define SQL_HANDLE_DESC 4 #endif +// The following types are our own equivalents of ODBC and Native Client +// ODBC driver types. They are all PODs and should be layout-compatible +// with the original types, which means they can be used interchangeably. +// +namespace odb +{ + namespace mssql + { + // UCS-2 character type (SQLWCHAR). + // +#ifdef _WIN32 + typedef wchar_t ucs2_char; +#else + typedef unsigned short ucs2_char; +#endif + + // SQL_NUMERIC_STRUCT + // +#ifndef SQL_MAX_NUMERIC_LEN +#define SQL_MAX_NUMERIC_LEN 16 +#else +# if SQL_MAX_NUMERIC_LEN != 16 +# error unexpected SQL_NUMERIC_STRUCT value +# endif +#endif + + struct decimal + { + unsigned char precision; + signed char scale; + unsigned char sign; // 1 - positive, 0 - negative + unsigned char val[SQL_MAX_NUMERIC_LEN]; + }; + + // DBMONEY + // + struct money + { + // 8-byte signed integer containing value * 10,000. + // + int high; + unsigned int low; + }; + + // DBMONEY4 + // + struct smallmoney + { + int value; // 4-byte signed integer containing value * 10,000. + }; + + //@@ TODO + // + struct date {}; + struct time {}; + struct datetime {}; + struct datetimeoffset {}; + } +} + #include <odb/post.hxx> #endif // ODB_MSSQL_MSSQL_FWD_HXX diff --git a/odb/mssql/mssql-types.hxx b/odb/mssql/mssql-types.hxx index 2ce7940..caedda3 100644 --- a/odb/mssql/mssql-types.hxx +++ b/odb/mssql/mssql-types.hxx @@ -87,12 +87,10 @@ namespace odb int_, // Buffer is a 4-byte integer. bigint, // Buffer is an 8-byte integer. - /* - numeric, // Buffer is an SQL_NUMERIC_STRUCT. + decimal, // Buffer is a decimal struct (SQL_NUMERIC_STRUCT). - smallmoney, // Buffer is a 4-byte integer (*10,000 value). - money, // Buffer is an 8-byte integer (*10,000 value). - */ + smallmoney, // Buffer is a smallmoney struct (DBMONEY4). + money, // Buffer is a money struct (DBMONEY). float4, // Buffer is a float. float8, // Buffer is a double. @@ -124,6 +122,9 @@ namespace odb SQLLEN* size_ind; // Pointer to the size/inidicator variable. SQLLEN capacity; // Buffer capacity. For string/binary parameters // this value is also used as maximum column size. + // For decimal parameters it contains precision (p) + // and scale (s) encoded as (p * 100 + s). For float4 + // and float8 it contains precision. }; } } diff --git a/odb/mssql/statement.cxx b/odb/mssql/statement.cxx index 8e61d82..0f05e95 100644 --- a/odb/mssql/statement.cxx +++ b/odb/mssql/statement.cxx @@ -31,8 +31,12 @@ namespace odb SQL_INTEGER, // bind::integer SQL_BIGINT, // bind::bigint - SQL_REAL, // bind::float4 - SQL_DOUBLE, // bind::float8 + SQL_DECIMAL, // bind::decimal + SQL_DECIMAL, // bind::smallmoney + SQL_DECIMAL, // bind::money + + SQL_FLOAT, // bind::float4 + SQL_FLOAT, // bind::float8 SQL_VARCHAR, // bind::string SQL_VARCHAR, // bind::long_string @@ -54,6 +58,10 @@ namespace odb SQL_C_SLONG, // bind::integer SQL_C_SBIGINT, // bind::bigint + SQL_C_NUMERIC, // bind::decimal + SQL_C_BINARY, // bind::smallmoney + SQL_C_BINARY, // bind::money + SQL_C_FLOAT, // bind::float4 SQL_C_DOUBLE, // bind::float8 @@ -170,10 +178,39 @@ namespace odb for (size_t i (1); i < n; ++i, ++b) { SQLULEN col_size; + SQLSMALLINT digits (0); SQLPOINTER buf; switch (b->type) { + case bind::decimal: + { + buf = (SQLPOINTER) b->buffer; + col_size = (SQLULEN) (b->capacity / 100); // precision + digits = (SQLSMALLINT) (b->capacity % 100); // scale + break; + } + case bind::smallmoney: + { + buf = (SQLPOINTER) b->buffer; + col_size = 10; + digits = 4; + break; + } + case bind::money: + { + buf = (SQLPOINTER) b->buffer; + col_size = 19; + digits = 4; + break; + } + case bind::float4: + case bind::float8: + { + buf = (SQLPOINTER) b->buffer; + col_size = (SQLULEN) b->capacity; // precision + break; + } case bind::long_string: case bind::long_binary: { @@ -207,6 +244,7 @@ namespace odb default: { buf = (SQLPOINTER) b->buffer; + col_size = 0; break; } } @@ -218,7 +256,7 @@ namespace odb c_type_lookup[b->type], sql_type_lookup[b->type], col_size, - 0, // decimal digits + digits, buf, 0, // buffer capacity (shouldn't be needed for input parameters) b->size_ind); @@ -236,8 +274,35 @@ namespace odb size_t i (0); for (bind* end (b + n); b != end; ++b) { + SQLLEN cap; + switch (b->type) { + case bind::decimal: + { + cap = (SQLLEN) sizeof (decimal); + break; + } + case bind::smallmoney: + { + cap = (SQLLEN) sizeof (smallmoney); + break; + } + case bind::money: + { + cap = (SQLLEN) sizeof (money); + break; + } + case bind::float4: + { + cap = (SQLLEN) sizeof (float); + break; + } + case bind::float8: + { + cap = (SQLLEN) sizeof (double); + break; + } case bind::long_string: case bind::long_nstring: case bind::long_binary: @@ -248,6 +313,7 @@ namespace odb } default: { + cap = b->capacity; break; } } @@ -256,7 +322,7 @@ namespace odb (SQLUSMALLINT) (i + 1), // Results are counted from 1. c_type_lookup[b->type], (SQLPOINTER) b->buffer, - b->capacity, + cap, b->size_ind); if (!SQL_SUCCEEDED (r)) diff --git a/odb/mssql/traits.cxx b/odb/mssql/traits.cxx new file mode 100644 index 0000000..6c625c6 --- /dev/null +++ b/odb/mssql/traits.cxx @@ -0,0 +1,15 @@ +// file : odb/mssql/traits.cxx +// author : Constantin Michael <constantin@codesynthesis.com> +// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC +// license : ODB NCUEL; see accompanying LICENSE file + +#include <odb/mssql/traits.hxx> + +using namespace std; + +namespace odb +{ + namespace mssql + { + } +} diff --git a/odb/mssql/traits.hxx b/odb/mssql/traits.hxx new file mode 100644 index 0000000..28188cb --- /dev/null +++ b/odb/mssql/traits.hxx @@ -0,0 +1,498 @@ +// file : odb/mssql/traits.hxx +// author : Constantin Michael <constantin@codesynthesis.com> +// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_TRAITS_HXX +#define ODB_MSSQL_TRAITS_HXX + +#include <odb/pre.hxx> + +#include <string> +#include <vector> +#include <cstddef> // std::size_t +//@@ #include <cstring> // std::memcpy, std::memset, std::strlen +//@@ #include <cassert> + +#include <odb/traits.hxx> +#include <odb/wrapper-traits.hxx> + +#include <odb/mssql/version.hxx> +#include <odb/mssql/mssql-types.hxx> + +#include <odb/details/buffer.hxx> +#include <odb/details/wrapper-p.hxx> + +#include <odb/mssql/details/export.hxx> + +namespace odb +{ + namespace mssql + { + enum database_type_id + { + id_bit, + id_tinyint, + id_smallint, + id_int, + id_bigint, + + id_decimal, // DECIMAL; NUMERIC + + id_smallmoney, + id_money, + + id_float4, // REAL; FLOAT(n) with n <= 24 + id_float8, // FLOAT(n) with n > 24 + + id_string, // CHAR(n), VARCHAR(n) with n <= N + id_long_string, // CHAR(n), VARCHAR(n) with n > N; TEXT + + id_nstring, // NCHAR(n), NVARCHAR(n) with 2*n <= N + id_long_nstring, // NCHAR(n), NVARCHAR(n) with 2*n > N; NTEXT + + id_binary, // BINARY(n), VARBINARY(n) with n <= N + id_long_binary, // BINARY(n), VARBINARY(n) with n > N; IMAGE + + id_date, // DATE + id_time, // TIME + id_datetime, // DATETIME; DATETIME2; SMALLDATETIME + id_datetimeoffset, // DATETIMEOFFSET + + id_uuid, // UNIQUEIDENTIFIER + id_rowversion // ROWVERSION; TIMESTAMP + }; + + // + // image_traits + // + + template <database_type_id> + struct image_traits; + + template <> + struct image_traits<id_bit> {typedef unsigned char image_type;}; + + template <> + struct image_traits<id_tinyint> {typedef unsigned char image_type;}; + + template <> + struct image_traits<id_smallint> {typedef short image_type;}; + + template <> + struct image_traits<id_int> {typedef int image_type;}; + + template <> + struct image_traits<id_bigint> {typedef long long image_type;}; + + template <> + struct image_traits<id_decimal> {typedef decimal image_type;}; + + template <> + struct image_traits<id_smallmoney> {typedef smallmoney image_type;}; + + template <> + struct image_traits<id_money> {typedef money image_type;}; + + template <> + struct image_traits<id_float4> {typedef float image_type;}; + + template <> + struct image_traits<id_float8> {typedef double image_type;}; + + template <> + struct image_traits<id_string> {typedef char* image_type;}; + + template <> + struct image_traits<id_long_string> {typedef long_callback image_type;}; + + template <> + struct image_traits<id_nstring> {typedef ucs2_char* image_type;}; + + template <> + struct image_traits<id_long_nstring> {typedef long_callback image_type;}; + + template <> + struct image_traits<id_binary> {typedef char* image_type;}; + + template <> + struct image_traits<id_long_binary> {typedef long_callback image_type;}; + + template <> + struct image_traits<id_date> {typedef date image_type;}; + + template <> + struct image_traits<id_time> {typedef time image_type;}; + + template <> + struct image_traits<id_datetime> {typedef datetime image_type;}; + + template <> + struct image_traits<id_datetimeoffset> {typedef datetimeoffset image_type;}; + + // Image is a 16-byte sequence. + // + template <> + struct image_traits<id_uuid> {typedef unsigned char* image_type;}; + + // Image is an 8-byte sequence. + // + template <> + struct image_traits<id_rowversion> {typedef unsigned char* image_type;}; + + // + // value_traits + // + + template <typename W, database_type_id, bool null_handler> + struct wrapped_value_traits; + + template <typename T, database_type_id> + struct default_value_traits; + + template <typename T, database_type_id, bool w = details::wrapper_p<T>::r> + struct select_traits; + + template <typename T, database_type_id ID> + struct select_traits<T, ID, false> + { + typedef default_value_traits<T, ID> type; + }; + + template <typename W, database_type_id ID> + struct select_traits<W, ID, true> + { + typedef + wrapped_value_traits<W, ID, wrapper_traits<W>::null_handler> + type; + }; + + template <typename T, database_type_id ID> + class value_traits: public select_traits<T, ID>::type + { + }; + + // The wrapped_value_traits specializations should be able to handle + // any value type which means we have to have every possible signature + // of the set_value() and set_image() functions. + // + template <typename W, database_type_id ID> + struct wrapped_value_traits<W, ID, false> + { + typedef wrapper_traits<W> wtraits; + typedef typename wtraits::unrestricted_wrapped_type wrapped_type; + + typedef W value_type; + typedef wrapped_type query_type; + typedef typename image_traits<ID>::image_type image_type; + + typedef value_traits<wrapped_type, ID> vtraits; + + static void + set_value (W& v, const image_type& i, bool is_null) + { + vtraits::set_value (wtraits::set_ref (v), i, is_null); + } + + static void + set_image (image_type& i, bool& is_null, const W& v) + { + vtraits::set_image (i, is_null, wtraits::get_ref (v)); + } + + /* + @@ TODO + + // big_int, big_float, string, nstring, raw. + // + static void + set_value (W& v, const char* i, std::size_t n, bool is_null) + { + vtraits::set_value (wtraits::set_ref (v), i, n, is_null); + } + + // string, nstring, raw. + // + static void + set_image (char* i, + std::size_t c, + std::size_t& n, + bool& is_null, + const W& v) + { + vtraits::set_image (i, c, n, is_null, wtraits::get_ref (v)); + } + + // big_int, big_float. + // + static void + set_image (char* i, std::size_t& n, bool& is_null, const W& v) + { + vtraits::set_image (i, n, is_null, wtraits::get_ref (v)); + } + + // blob, clob, nclob. + // + static void + set_value (W& v, result_callback_type& cb, void*& context, bool is_null) + { + vtraits::set_value (wtraits::set_ref (v), cb, context, is_null); + } + + static void + set_image (param_callback_type& cb, + const void*& context, + bool& is_null, + const W& v) + { + vtraits::set_image (cb, context, is_null, wtraits::get_ref (v)); + } + */ + }; + + template <typename W, database_type_id ID> + struct wrapped_value_traits<W, ID, true> + { + typedef wrapper_traits<W> wtraits; + typedef typename wtraits::unrestricted_wrapped_type wrapped_type; + + typedef W value_type; + typedef wrapped_type query_type; + typedef typename image_traits<ID>::image_type image_type; + + typedef value_traits<wrapped_type, ID> vtraits; + + static void + set_value (W& v, const image_type& i, bool is_null) + { + if (is_null) + wtraits::set_null (v); + else + vtraits::set_value (wtraits::set_ref (v), i, is_null); + } + + static void + set_image (image_type& i, bool& is_null, const W& v) + { + is_null = wtraits::get_null (v); + + if (!is_null) + vtraits::set_image (i, is_null, wtraits::get_ref (v)); + } + + /* + @@ TODO + + // big_int, big_float, string, nstring, raw. + // + static void + set_value (W& v, const char* i, std::size_t n, bool is_null) + { + if (is_null) + wtraits::set_null (v); + else + vtraits::set_value (wtraits::set_ref (v), i, n, is_null); + } + + // string, nstring, raw. + // + static void + set_image (char* i, + std::size_t c, + std::size_t& n, + bool& is_null, + const W& v) + { + is_null = wtraits::get_null (v); + + if (!is_null) + vtraits::set_image (i, c, n, is_null, wtraits::get_ref (v)); + } + + // big_int, big_float + // + static void + set_image (char* i, std::size_t& n, bool& is_null, const W& v) + { + is_null = wtraits::get_null (v); + + if (!is_null) + vtraits::set_image (i, n, is_null, wtraits::get_ref (v)); + } + + // blob, clob, nclob. + // + static void + set_value (W& v, result_callback_type& cb, void*& context, bool is_null) + { + if (is_null) + wtraits::set_null (v); + else + vtraits::set_value (wtraits::set_ref (v), cb, context, is_null); + } + + static void + set_image (param_callback_type& cb, + const void*& context, + bool& is_null, + const W& v) + { + is_null = wtraits::get_null (v); + + if (!is_null) + vtraits::set_image (cb, context, is_null, wtraits::get_ref (v)); + } + */ + }; + + template <typename T, database_type_id ID> + struct default_value_traits + { + typedef T value_type; + typedef T query_type; + typedef typename image_traits<ID>::image_type image_type; + + static void + set_value (T& v, const image_type& i, bool is_null) + { + if (!is_null) + v = T (i); + else + v = T (); + } + + static void + set_image (image_type& i, bool& is_null, T v) + { + is_null = false; + i = image_type (v); + } + }; + + // + // type_traits + // + + template <typename T> + struct default_type_traits; + + template <typename T> + class type_traits: public default_type_traits<T> + { + }; + + // Integral types. + // + template <> + struct default_type_traits<bool> + { + static const database_type_id db_type_id = id_bit; + }; + + template <> + struct default_type_traits<signed char> + { + static const database_type_id db_type_id = id_tinyint; + }; + + template <> + struct default_type_traits<unsigned char> + { + static const database_type_id db_type_id = id_tinyint; + }; + + template <> + struct default_type_traits<short> + { + static const database_type_id db_type_id = id_smallint; + }; + + template <> + struct default_type_traits<unsigned short> + { + static const database_type_id db_type_id = id_smallint; + }; + + template <> + struct default_type_traits<int> + { + static const database_type_id db_type_id = id_int; + }; + + template <> + struct default_type_traits<unsigned int> + { + static const database_type_id db_type_id = id_int; + }; + + template <> + struct default_type_traits<long> + { + static const database_type_id db_type_id = id_bigint; + }; + + template <> + struct default_type_traits<unsigned long> + { + static const database_type_id db_type_id = id_bigint; + }; + + template <> + struct default_type_traits<long long> + { + static const database_type_id db_type_id = id_bigint; + }; + + template <> + struct default_type_traits<unsigned long long> + { + static const database_type_id db_type_id = id_bigint; + }; + + // Float types. + // + template <> + struct default_type_traits<float> + { + static const database_type_id db_type_id = id_float4; + }; + + template <> + struct default_type_traits<double> + { + static const database_type_id db_type_id = id_float8; + }; + + // String type. + // + template <> + struct default_type_traits<std::string> + { + static const database_type_id db_type_id = id_long_string; + }; + + template <> + struct default_type_traits<const char*> + { + static const database_type_id db_type_id = id_long_string; + }; + + template <std::size_t n> + struct default_type_traits<char[n]> + { + static const database_type_id db_type_id = id_long_string; + }; + + template <std::size_t n> + struct default_type_traits<const char[n]> + { + static const database_type_id db_type_id = id_long_string; + }; + } +} + +#include <odb/mssql/traits.txx> + +#include <odb/post.hxx> + +#endif // ODB_MSSQL_TRAITS_HXX diff --git a/odb/mssql/traits.txx b/odb/mssql/traits.txx new file mode 100644 index 0000000..b3bc442 --- /dev/null +++ b/odb/mssql/traits.txx @@ -0,0 +1,11 @@ +// file : odb/mssql/traits.txx +// author : Constantin Michael <constantin@codesynthesis.com> +// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC +// license : ODB NCUEL; see accompanying LICENSE file + +namespace odb +{ + namespace mssql + { + } +} |