From a64b2d953da436bdca5cf35329d10fd95e1ae860 Mon Sep 17 00:00:00 2001 From: Constantin Michael Date: Thu, 20 Oct 2011 10:13:51 +0200 Subject: Use SQLT_NUM instead of SQLT_VNU OCI type due to inconsistent buffer lengths The size returned by OCI into the bound rlen parameter of a SQLT_VNU buffer does not include the additional length byte. This causes problems with images that are shared across multiple statements in ODB, such as the object_id image of containers. --- odb/oracle/details/number.cxx | 72 +++++++++++++++++++------------------------ odb/oracle/details/number.hxx | 4 +-- odb/oracle/statement.cxx | 4 +-- odb/oracle/traits.hxx | 72 +++++++++++++++++-------------------------- 4 files changed, 64 insertions(+), 88 deletions(-) diff --git a/odb/oracle/details/number.cxx b/odb/oracle/details/number.cxx index e62894d..6c0a56c 100644 --- a/odb/oracle/details/number.cxx +++ b/odb/oracle/details/number.cxx @@ -16,38 +16,32 @@ namespace odb { namespace details { - // The VARNUM type's binary representation is made up of the following + // The NUMBER type's binary representation is made up of the following // bit fields, ordered in increasing memory address. // - // 000 to 007: The size of the binary representation, including the - // exponent bits and the mantissa bits, but excluding these - // length bits. - // - // 008 to 015: The base-100 exponent bits. The most significant bit is + // 000 to 007: The base-100 exponent bits. The most significant bit is // the sign bit of the number, which is set for positive // numbers and cleared for negative numbers. For positive // numbers, the exponent has a bias of 65 added to it. // - // 016 to 175: The mantissa bits. Each byte of this field represents a + // 008 to 167: The mantissa bits. Each byte of this field represents a // single base-100 value. // // long long - number_to_int64 (const char* b) + number_to_int64 (const char* b, size_t n) { // All bytes in the buffer are interpreted as unsigned. // const unsigned char* ub (reinterpret_cast (b)); - int n (ub[0]); - // Zero is represented by zero significant bits and an exponent // set to 128. // if (n == 1) { - assert (ub[1] == 128); + assert (ub[0] == 128); return 0; } @@ -55,21 +49,21 @@ namespace odb // Test the sign bit of the exponent. // - if ((ub[1] & 0x80) != 0) + if ((ub[0] & 0x80) != 0) { // The unbiased exponent of a positive number may be calculated as - // ub[1] - 128 - 65. For an integer, this is the order of magnitude + // ub[0 - 128 - 65. For an integer, this is the order of magnitude // of the number. Calculate the maximum weight, 100 ^ o, where o is // the order of magnitude of the number. // long long w (1); - for (size_t i (0), o (ub[1] - 193); i < o; ++i) + for (size_t i (0), o (ub[0] - 193); i < o; ++i) w *= 100; // Accumlate the sum of the significant base-100 terms. // - for (const unsigned char* m (ub + 2), *e (ub + 1 + n); m < e; ++m) + for (const unsigned char* m (ub + 1), *e (ub + n); m < e; ++m) { v += (*m - 1) * w; w /= 100; @@ -78,20 +72,20 @@ namespace odb else { // The unbiased exponent of a negative number is calculated as - // (~ub[1] & 0x7F) - 193. For an integer, this is the order of + // (~ub[0] & 0x7F) - 193. For an integer, this is the order of // magnitude of the number. Calculate the maximum weight, 100 ^ o, // where o is the order of magnitude of the number. // long long w (1); - for (size_t i (0), o ((~ub[1] & 0x7F) - 65); i < o; ++i) + for (size_t i (0), o ((~ub[0] & 0x7F) - 65); i < o; ++i) w *= 100; // Accumulate the sum of the significant base-100 terms. Note that // negative values will have a terminator byte which is included // in the length. This is ignored. // - for (const unsigned char* m (ub + 2), *e (ub + n); m < e; ++m) + for (const unsigned char* m (ub + 1), *e (ub + n - 1); m < e; ++m) { v -= (101 - *m) * w; w /= 100; @@ -104,7 +98,7 @@ namespace odb void int64_to_number (char* b, size_t& n, long long v) { - // We assume that b is long enough to contain a long long VARNUM + // We assume that b is long enough to contain a long long NUMBER // representation, that being 12 bytes. // @@ -114,8 +108,8 @@ namespace odb if (v == 0) { - ub[0] = 1; - ub[1] = 128; + ub[0] = 128; + n = 1; return; } @@ -145,7 +139,7 @@ namespace odb // The exponent is one less than the number of base 100 digits. It is // inverted for negative values. // - ub[1] = static_cast (~(n + 192)); + ub[0] = static_cast (~(n + 192)); } else { @@ -163,36 +157,33 @@ namespace odb // Exponent is one less than the number of base 100 digits. // - ub[1] = static_cast (n + 192); + ub[0] = static_cast (n + 192); } // Set the length. // - ub[0] = static_cast (m - t + 1); - n = static_cast (ub[0] + 1); + n = static_cast (m - t + 1); // Set the significant digits in big-endian byte order and the // terminator, if any. // - for (size_t i (2); m > t; ++i) + for (size_t i (1); m > t; ++i) ub[i] = *--m; } unsigned long long - number_to_uint64 (const char* b) + number_to_uint64 (const char* b, size_t n) { // All bytes in the buffer are interpreted as unsigned. // const unsigned char* ub (reinterpret_cast (b)); - int n (ub[0]); - // Zero is represented by zero significant bits and an exponent // set to 128. // if (n == 1) { - assert (ub[1] == 128); + assert (ub[0] == 128); return 0; } @@ -200,25 +191,25 @@ namespace odb // Test the sign bit of the exponent. // - if ((ub[1] & 0x80) == 0) + if ((ub[0] & 0x80) == 0) { assert (false); return 0; } // The unbiased exponent of a positive number may be calculated as - // ub[1] - 128 - 65. For an integer, this is the order of magnitude + // ub[0] - 128 - 65. For an integer, this is the order of magnitude // of the number. Calculate the maximum weight, 100 ^ o, where o is // the order of magnitude of the number. // unsigned long long w (1); - for (size_t i (0), o (ub[1] - 193); i < o; ++i) + for (size_t i (0), o (ub[0] - 193); i < o; ++i) w *= 100; // Accumlate the sum of the significant base-100 terms. // - for (const unsigned char* m (ub + 2), *e (ub + 1 + n); m < e; ++m) + for (const unsigned char* m (ub + 1), *e (ub + n); m < e; ++m) { v += (*m - 1) * w; w /= 100; @@ -231,7 +222,7 @@ namespace odb uint64_to_number (char* b, size_t& n, unsigned long long v) { // We assume that b is long enough to contain an unsigned long long - // VARNUM representation, that being 12 bytes. + // NUMBER representation, that being 12 bytes. // // All bytes in the buffer are interpreted as unsigned. @@ -240,8 +231,8 @@ namespace odb if (v == 0) { - ub[0] = 1; - ub[1] = 128; + ub[0] = 128; + n = 1; return; } @@ -264,16 +255,15 @@ namespace odb // Exponent is one less than the number of base 100 digits. // - ub[1] = static_cast (n + 192); + ub[0] = static_cast (n + 192); // Set the length. // - ub[0] = static_cast (m - t + 1); - n = static_cast (ub[0] + 1); + n = static_cast (m - t + 1); // Set the significant digits in big-endian byte order. // - for (size_t i (2); m > t; ++i) + for (size_t i (1); m > t; ++i) ub[i] = *--m; } } diff --git a/odb/oracle/details/number.hxx b/odb/oracle/details/number.hxx index 90fb038..3b10a3c 100644 --- a/odb/oracle/details/number.hxx +++ b/odb/oracle/details/number.hxx @@ -27,13 +27,13 @@ namespace odb using namespace odb::details; LIBODB_ORACLE_EXPORT long long - number_to_int64 (const char* buffer); + number_to_int64 (const char* buffer, std::size_t n); LIBODB_ORACLE_EXPORT void int64_to_number (char* buffer, std::size_t& n, long long val); LIBODB_ORACLE_EXPORT unsigned long long - number_to_uint64 (const char* buffer); + number_to_uint64 (const char* buffer, std::size_t n); LIBODB_ORACLE_EXPORT void uint64_to_number (char* buffer, std::size_t& n, unsigned long long val); diff --git a/odb/oracle/statement.cxx b/odb/oracle/statement.cxx index 7233e05..d63e4a7 100644 --- a/odb/oracle/statement.cxx +++ b/odb/oracle/statement.cxx @@ -33,7 +33,7 @@ namespace odb SQLT_UIN, // bind::uinteger SQLT_BFLOAT, // bind::binary_float SQLT_BDOUBLE, // bind::binary_double - SQLT_VNU, // bind::number + SQLT_NUM, // bind::number SQLT_DAT, // bind::date SQLT_TIMESTAMP, // bind::timestamp SQLT_CHR, // bind::string @@ -53,7 +53,7 @@ namespace odb SQLT_UIN, // bind::uinteger SQLT_BFLOAT, // bind::binary_float SQLT_BDOUBLE, // bind::binary_double - SQLT_VNU, // bind::number + SQLT_NUM, // bind::number SQLT_DAT, // bind::date SQLT_TIMESTAMP, // bind::timestamp SQLT_CHR, // bind::string diff --git a/odb/oracle/traits.hxx b/odb/oracle/traits.hxx index 6bcc1ac..0458aef 100644 --- a/odb/oracle/traits.hxx +++ b/odb/oracle/traits.hxx @@ -8,9 +8,6 @@ #include -// @@ -#include - #include #include #include // std::size_t @@ -263,21 +260,7 @@ namespace odb vtraits::set_image (i, is_null, wtraits::get_ref (v)); } - // big_int, big_float. - // - static void - set_value (W& v, const char* i, bool is_null) - { - vtraits::set_value (wtraits::set_ref (v), i, is_null); - } - - 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)); - } - - // timestamp, string, nstring, raw. + // big_int, big_float, timestamp, string, nstring, raw. // static void set_value (W& v, const char* i, std::size_t n, bool is_null) @@ -285,6 +268,8 @@ namespace odb vtraits::set_value (wtraits::set_ref (v), i, n, is_null); } + // timestamp, string, nstring, raw. + // static void set_image (char* i, std::size_t c, @@ -295,6 +280,14 @@ namespace odb 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 @@ -343,27 +336,7 @@ namespace odb vtraits::set_image (i, is_null, wtraits::get_ref (v)); } - // big_int, big_float. - // - static void - set_value (W& v, const char& 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 (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)); - } - - // timestamp, string, nstring, raw. + // big_int, big_float, timestamp, string, nstring, raw. // static void set_value (W& v, const char* i, std::size_t n, bool is_null) @@ -374,6 +347,8 @@ namespace odb vtraits::set_value (wtraits::set_ref (v), i, n, is_null); } + // timestamp, string, nstring, raw. + // static void set_image (char* i, std::size_t c, @@ -387,6 +362,17 @@ namespace odb 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 @@ -444,10 +430,10 @@ namespace odb struct big_int_value_traits { static void - set_value (T& v, const char* b, bool is_null) + set_value (T& v, const char* b, std::size_t n, bool is_null) { if (!is_null) - v = static_cast (details::number_to_int64 (b)); + v = static_cast (details::number_to_int64 (b, n)); else v = 0; } @@ -464,10 +450,10 @@ namespace odb struct big_int_value_traits { static void - set_value (T& v, const char* b, bool is_null) + set_value (T& v, const char* b, std::size_t n, bool is_null) { if (!is_null) - v = static_cast (details::number_to_uint64 (b)); + v = static_cast (details::number_to_uint64 (b, n)); else v = 0; } -- cgit v1.1