diff options
Diffstat (limited to 'odb-tests/oracle/types')
-rw-r--r-- | odb-tests/oracle/types/buildfile | 35 | ||||
-rw-r--r-- | odb-tests/oracle/types/driver.cxx | 364 | ||||
-rw-r--r-- | odb-tests/oracle/types/test.hxx | 347 | ||||
-rw-r--r-- | odb-tests/oracle/types/testscript | 11 | ||||
-rw-r--r-- | odb-tests/oracle/types/traits.hxx | 192 |
5 files changed, 949 insertions, 0 deletions
diff --git a/odb-tests/oracle/types/buildfile b/odb-tests/oracle/types/buildfile new file mode 100644 index 0000000..ff8eb8d --- /dev/null +++ b/odb-tests/oracle/types/buildfile @@ -0,0 +1,35 @@ +# file : oracle/types/buildfile +# license : GNU GPL v2; see accompanying LICENSE file + +if ($build.meta_operation != 'dist') +{ + assert ($oracle) "oracle should be configured for this test" + assert (!$multi) "multi-database mode is not supported by this test" +} + +import libodb = libodb%lib{odb} + +import libs = libodb-oracle%lib{odb-oracle} +import libs += lib{common} + +exe{driver}: {hxx cxx}{* -*-odb} {hxx ixx cxx}{test-odb} testscript + +# Introduce the metadata library target to make sure the libodb library is +# resolved for the odb_compile ad hoc rule (see build/root.build for details). +# +libue{test-meta}: $libodb + +<{hxx ixx cxx}{test-odb}>: hxx{test} libue{test-meta} + +exe{driver}: libue{test-meta} $libs + +# Specify the ODB custom options to be used by the odb_compile ad hoc rule +# (see build/root.build for details). +# +odb_options = --table-prefix oracle_types_ \ + --generate-schema \ + --default-database common \ + --generate-query \ + --hxx-prologue '#include "traits.hxx"' + +cxx.poptions =+ "-I$out_base" "-I$src_base" diff --git a/odb-tests/oracle/types/driver.cxx b/odb-tests/oracle/types/driver.cxx new file mode 100644 index 0000000..2730f1a --- /dev/null +++ b/odb-tests/oracle/types/driver.cxx @@ -0,0 +1,364 @@ +// file : oracle/types/driver.cxx +// license : GNU GPL v2; see accompanying LICENSE file + +// Test Oracle type conversion. +// + +#include <memory> // std::unique_ptr +#include <iostream> + +#include <odb/oracle/database.hxx> +#include <odb/oracle/transaction.hxx> + +#include <libcommon/common.hxx> + +#include "test.hxx" +#include "test-odb.hxx" + +#undef NDEBUG +#include <cassert> + +using namespace std; +namespace oracle = odb::oracle; +using namespace oracle; + +int +main (int argc, char* argv[]) +{ + try + { + // Create an Oracle database instance, setting both the client database + // and national character set to UTF-8. + // + unique_ptr<database> db (create_specific_database<database> (argc, argv)); + + object o (1); + + o.int_ = -123456; + o.uint_ = 123456; + o.long_long_ = -123456; + o.ulong_long_ = 123456; + + o.float_ = 1.123F; + o.double_ = 1.123; + o.num_float_ = 1.123F; + o.num_double_ = 1.123; + o.binary_float_ = 1.123F; + o.binary_double_ = 1.123; + + o.date_ = date_time (2010, 8, 29, 15, 33, 18, 0); + o.timestamp_ = date_time (1996, 3, 9, 18, 2, 54, 123000); + o.interval_ds_ = time_interval (0, 0, 13, 15, 23, 19, 123000); + o.interval_ym_ = time_interval (12, 3, 0, 0, 0, 0, 0); + + string vshort_str (8, 's'); + string short_str (13, 's'); + string medium_str (104, 'm'); + string long_str (1018, 'l'); + string vlong_str (15000, 'v'); + + o.char_ = short_str; + o.varchar2_ = medium_str; + o.clob_.assign (vlong_str.data (), vlong_str.data () + vlong_str.size ()); + + o.nchar_ = vshort_str; + o.nvarchar2_ = medium_str; + o.nclob_.assign (vlong_str.data (), vlong_str.data () + vlong_str.size ()); + + o.empty_c_.push_back (""); + + o.raw_.assign (long_str.data (), long_str.data () + long_str.size ()); + o.blob_.assign (vlong_str.data (), vlong_str.data () + vlong_str.size ()); + + o.strs_.push_back (short_str); + o.strs_.push_back (medium_str); + o.strs_.push_back (long_str); + o.strs_.push_back (vlong_str); + + // Persist. + // + { + transaction t (db->begin ()); + db->persist (o); + t.commit (); + } + + // Load. + // + { + transaction t (db->begin ()); + unique_ptr<object> o1 (db->load<object> (1)); + t.commit (); + + assert (o == *o1); + } + + // Test character set conversion. + // + const char* unicode_str = "a \xD5\x95 \xEA\xAA\xAA \xF2\xAA\xAA\xAA"; + + // Testing of character set conversion to and from the client's database + // character set is disabled as the server database character set may + // not be able to represent some Unicode characters. If this were the case + // the test outcome would be a false negative. + // + // o.char_ = unicode_str; + // o.varchar2_ = unicode_str; + // o.clob_ = unicode_str; + + o.nchar_ = unicode_str; + o.nvarchar2_ = unicode_str; + o.nclob_ = unicode_str; + + // Persist. + // + { + transaction t (db->begin ()); + db->update (o); + t.commit (); + } + + // Load. + // + { + transaction t (db->begin ()); + unique_ptr<object> o1 (db->load<object> (1)); + t.commit (); + + assert (o == *o1); + } + + // Test 64 bit integers. + // + big_int bi1 (1, 0x8000000000000000LL); + big_int bi2 (2, -123456); + big_int bi3 (3, 0); + big_int bi4 (4, 123456); + big_int bi5 (5, 0xFFFFFFFFFFFFFFFFULL); + + big_uint bui1 (1, 0); + big_uint bui2 (2, 123456); + big_uint bui3 (3, 0xFFFFFFFFFFFFFFFFULL); + + // Persist. + // + { + transaction t (db->begin ()); + db->persist (bi1); + db->persist (bi2); + db->persist (bi3); + db->persist (bi4); + db->persist (bi5); + db->persist (bui1); + db->persist (bui2); + db->persist (bui3); + t.commit (); + } + + // Load. + // + { + transaction t (db->begin ()); + unique_ptr<big_int> bil1 (db->load<big_int> (1)); + unique_ptr<big_int> bil2 (db->load<big_int> (2)); + unique_ptr<big_int> bil3 (db->load<big_int> (3)); + unique_ptr<big_int> bil4 (db->load<big_int> (4)); + unique_ptr<big_int> bil5 (db->load<big_int> (5)); + unique_ptr<big_uint> buil1 (db->load<big_uint> (1)); + unique_ptr<big_uint> buil2 (db->load<big_uint> (2)); + unique_ptr<big_uint> buil3 (db->load<big_uint> (3)); + t.commit (); + + assert (bi1 == *bil1); + assert (bi2 == *bil2); + assert (bi3 == *bil3); + assert (bi4 == *bil4); + assert (bi5 == *bil5); + assert (bui1 == *buil1); + assert (bui2 == *buil2); + assert (bui3 == *buil3); + } + + // Test large BLOBs. + // + descriptor b1 (1); + b1.blob.assign (50000, 'b'); + b1.timestamp = date_time (1996, 3, 9, 18, 2, 54, 123000); + b1.interval_ds = time_interval (0, 0, 13, 15, 23, 19, 123000); + b1.interval_ym = time_interval (12, 3, 0, 0, 0, 0, 0); + + descriptor b2 (2); + b2.blob.assign (500000, 'b'); + b2.timestamp = date_time (1997, 4, 10, 19, 3, 55, 234000); + b2.interval_ds = time_interval (0, 0, 14, 16, 24, 20, 234000); + b2.interval_ym = time_interval (13, 4, 0, 0, 0, 0, 0); + + descriptor b3 (3); + b3.blob.assign (5000, 'b'); + b3.timestamp = date_time (1995, 2, 8, 17, 1, 53, 120000); + b3.interval_ds = time_interval (0, 0, 12, 14, 22, 18, 120000); + b3.interval_ym = time_interval (11, 2, 0, 0, 0, 0, 0); + + // Persist. + // + { + transaction t (db->begin ()); + db->persist (b1); + db->persist (b2); + t.commit (); + } + + // Load. + // + { + transaction t (db->begin ()); + unique_ptr<descriptor> p1 (db->load<descriptor> (1)); + unique_ptr<descriptor> p2 (db->load<descriptor> (2)); + t.commit (); + + assert (b1 == *p1); + assert (b2 == *p2); + } + + // Test image copying with descriptor-based type (LOB, date-time) data. + // + { + typedef oracle::query<descriptor> query; + typedef odb::result<descriptor> result; + + transaction t (db->begin ()); + + // Pre-bind the image for other operations. + // + { + db->persist (b3); + db->update (b3); + db->reload (b3); + db->erase (b3); + } + + + result r (db->query<descriptor> (query::id < 3)); + result::iterator i (r.begin ()); + + assert (i != r.end ()); + + { + result r (db->query<descriptor> (query::id > 1)); + result::iterator i (r.begin ()); + assert (i != r.end ()); + assert (*i == b2); + assert (++i == r.end ()); + } + + assert (*i == b1); // Load from copy (copy c-tor). + + ++i; + assert (i != r.end ()); + + { + result r (db->query<descriptor> (query::id < 2)); + result::iterator i (r.begin ()); + assert (i != r.end ()); + assert (*i == b1); + assert (++i == r.end ()); + } + + assert (*i == b2); // Load from copy (copy assign). + assert (++i == r.end ()); + + // Make sure all other operations are still working. + // + { + db->persist (b3); + unique_ptr<descriptor> p (db->load<descriptor> (3)); + assert (b3 == *p); + b3.blob.push_back (123); + db->update (b3); + db->reload (p); + assert (b3 == *p); + db->erase (b3); + } + + t.commit (); + } + + // Test descriptor management in TIMESTAMP and INTERVAL images. + // + { + typedef oracle::query<object> query; + typedef odb::result<object> result; + + query q (query::timestamp == o.timestamp_ && + query::interval_ym == o.interval_ym_ && + query::interval_ds == o.interval_ds_); + + transaction t (db->begin ()); + + { + result r (db->query<object> (q)); + assert (size (r) == 1); + } + + { + result r (db->query<object> (q)); + assert (size (r) == 1); + } + + { + // Query temporary. + // + result r (db->query<object> ( + query::timestamp == o.timestamp_ && + query::interval_ym == o.interval_ym_ && + query::interval_ds == o.interval_ds_)); + + query dummy (query::timestamp == o.timestamp_ && + query::interval_ym == o.interval_ym_ && + query::interval_ds == o.interval_ds_); + + assert (size (r) == 1); + } + + t.commit (); + } + + // Test char array. + // + { + char_array o1 (1, ""); + char_array o2 (2, "1234567890"); + char_array o3 (3, "1234567890123456"); + + { + transaction t (db->begin ()); + db->persist (o1); + db->persist (o2); + db->persist (o3); + t.commit (); + } + + // Oracle returns padded values for CHAR(N) unless they are + // empty (represented as NULL). + // + memcpy (o2.s2, "1234567890 ", 16); + + { + transaction t (db->begin ()); + unique_ptr<char_array> p1 (db->load<char_array> (1)); + unique_ptr<char_array> p2 (db->load<char_array> (2)); + unique_ptr<char_array> p3 (db->load<char_array> (3)); + t.commit (); + + assert (o1 == *p1); + assert (o2 == *p2); + assert (o3 == *p3); + } + } + } + catch (const odb::exception& e) + { + cerr << e.what () << endl; + return 1; + } +} diff --git a/odb-tests/oracle/types/test.hxx b/odb-tests/oracle/types/test.hxx new file mode 100644 index 0000000..ee681c4 --- /dev/null +++ b/odb-tests/oracle/types/test.hxx @@ -0,0 +1,347 @@ +// file : oracle/types/test.hxx +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef TEST_HXX +#define TEST_HXX + +#include <string> +#include <vector> +#include <memory> // std::unique_ptr +#include <cstring> // std::memcpy, std::str[n]cmp, std::strlen + +#include <odb/core.hxx> + +struct date_time +{ + date_time () + { + } + + date_time (unsigned short y, + unsigned char m, + unsigned char d, + unsigned char h, + unsigned char min, + unsigned char sec, + unsigned int nsec) + : year (y), + month (m), + day (d), + hour (h), + minute (min), + second (sec), + nanosecond (nsec) + { + } + + bool + operator== (const date_time& y) const + { + return + year == y.year && + month == y.month && + day == y.day && + hour == y.hour && + minute == y.minute && + second == y.second && + nanosecond == y.nanosecond; + } + + unsigned short year; + unsigned char month; + unsigned char day; + unsigned char hour; + unsigned char minute; + unsigned char second; + unsigned int nanosecond; +}; + +struct time_interval +{ + time_interval () + { + } + + time_interval (int y, int m, int d, int h, int min, int sec, int nsec) + : year (y), + month (m), + day (d), + hour (h), + minute (min), + second (sec), + nanosecond (nsec) + { + } + + bool + operator== (const time_interval& y) const + { + return + year == y.year && + month == y.month && + day == y.day && + hour == y.hour && + minute == y.minute && + second == y.second && + nanosecond == y.nanosecond; + } + + int year; + int month; + int day; + int hour; + int minute; + int second; + int nanosecond; +}; + +typedef std::unique_ptr<std::string> string_ptr; + +typedef std::vector<std::string> strings; + +#pragma db object +struct object +{ + object () {} + object (unsigned long id): id_ (id) {} + + #pragma db id + unsigned int id_; + + // Integral types. + // + #pragma db type ("NUMBER(10)") + int int_; + + #pragma db type ("NUMBER(10)") + unsigned uint_; + + #pragma db type ("NUMBER(19)") + long long long_long_; + + #pragma db type ("NUMBER(20)") + unsigned long long ulong_long_; + + // Float types. + // + #pragma db type ("FLOAT(24)") + float float_; + + #pragma db type ("FLOAT(53)") + double double_; + + #pragma db type ("NUMBER(7,3)") + float num_float_; + + #pragma db type ("NUMBER(15,5)") + double num_double_; + + #pragma db type ("BINARY_FLOAT") + float binary_float_; + + #pragma db type ("BINARY_DOUBLE") + double binary_double_; + + // Data-time types. + // + #pragma db type ("DATE") + date_time date_; + + #pragma db type ("TIMESTAMP(6)") + date_time timestamp_; + + #pragma db type ("INTERVAL DAY TO SECOND") + time_interval interval_ds_; + + #pragma db type ("INTERVAL YEAR TO MONTH") + time_interval interval_ym_; + + // String and binary types. + // + #pragma db type ("CHAR(13)") + std::string char_; + + #pragma db type ("VARCHAR2(512)") null + std::string varchar2_; + + #pragma db type ("NCHAR(8)") + std::string nchar_; + + #pragma db type ("NVARCHAR2(512)") null + std::string nvarchar2_; + + // Oracle treats empty and NULL VARCHAR2 the same. Test that we + // handle this. + // + std::string empty_; + std::vector<std::string> empty_c_; + + #pragma db type ("RAW(1024)") + std::vector<char> raw_; + + // LOB types. + // + #pragma db type ("BLOB") + std::vector<char> blob_; + + #pragma db type ("CLOB") + std::string clob_; + + #pragma db type ("NCLOB") + std::string nclob_; + + // Test containers of LOBs + // + #pragma db value_type ("CLOB") + strings strs_; + + // Test NULL value. + // + #pragma db type ("VARCHAR2(32)") null + string_ptr null_; + + bool + operator== (const object& y) const + { + return + id_ == y.id_ && + int_ == y.int_ && + uint_ == y.uint_ && + long_long_ == y.long_long_ && + ulong_long_ == y.ulong_long_ && + float_ == y.float_ && + double_ == y.double_ && + num_float_ == y.num_float_ && + num_double_ == y.num_double_ && + binary_float_ == y.binary_float_ && + binary_double_ == y.binary_double_ && + date_ == y.date_ && + timestamp_ == y.timestamp_ && + interval_ds_ == y.interval_ds_ && + interval_ym_ == y.interval_ym_ && + char_ == y.char_ && + varchar2_ == y.varchar2_ && + nchar_ == y.nchar_ && + nvarchar2_ == y.nvarchar2_ && + empty_ == y.empty_ && + empty_c_ == y.empty_c_ && + raw_ == y.raw_ && + blob_ == y.blob_ && + clob_ == y.clob_ && + nclob_ == y.nclob_ && + strs_ == y.strs_ && + ((null_.get () == 0 && y.null_.get () == 0) || *null_ == *y.null_); + } +}; + +#pragma db object +struct big_uint +{ + big_uint (unsigned int id = 0, unsigned long long v = 0) + : id_ (id), value (v) + { + } + + #pragma db id + unsigned int id_; + + unsigned long long value; + + bool + operator== (const big_uint& y) const + { + return id_ == y.id_ && value == y.value; + } +}; + +#pragma db object +struct big_int +{ + big_int (unsigned int id = 0, long long v = 0) + : id_ (id), value (v) + { + } + + #pragma db id + unsigned int id_; + + long long value; + + bool + operator== (const big_int& y) const + { + return id_ == y.id_ && value == y.value; + } +}; + +#pragma db object +struct descriptor +{ + descriptor (unsigned int id = 0): id_ (id) {} + + #pragma db id + unsigned int id_; + + #pragma db type ("BLOB") + std::vector<char> blob; + + #pragma db type ("TIMESTAMP(6)") + date_time timestamp; + + #pragma db type ("INTERVAL DAY TO SECOND") + time_interval interval_ds; + + #pragma db type ("INTERVAL YEAR TO MONTH") + time_interval interval_ym; + + bool + operator== (const descriptor& y) const + { + return id_ == y.id_ && + blob == y.blob && + timestamp == y.timestamp && + interval_ds == y.interval_ds && + interval_ym == y.interval_ym; + } +}; + +// Test char array. +// +#pragma db object +struct char_array +{ + char_array () {} + char_array (unsigned long id, const char* s) + : id_ (id) + { + std::memcpy (s1, s, std::strlen (s) + 1); // VC++ strncpy deprecation. + std::memcpy (s2, s, std::strlen (s) + 1); + s3[0] = c1 = *s; + } + + #pragma db id + unsigned long id_; + + char s1[17]; + + #pragma db type("CHAR(16)") null + char s2[16]; + + #pragma db null + char s3[1]; + + #pragma db null + char c1; + + bool + operator== (const char_array& y) const + { + return id_ == y.id_ && + std::strcmp (s1, y.s1) == 0 && + std::strncmp (s2, y.s2, sizeof (s2)) == 0 && + s3[0] == y.s3[0] && + c1 == y.c1; + } +}; + +#endif // TEST_HXX diff --git a/odb-tests/oracle/types/testscript b/odb-tests/oracle/types/testscript new file mode 100644 index 0000000..daed1a3 --- /dev/null +++ b/odb-tests/oracle/types/testscript @@ -0,0 +1,11 @@ +# file : oracle/types/testscript +# license : GNU GPL v2; see accompanying LICENSE file + +.include ../../database-options.testscript +.include ../../oracle.testscript + ++$create_schema + +: basics +: +$* diff --git a/odb-tests/oracle/types/traits.hxx b/odb-tests/oracle/types/traits.hxx new file mode 100644 index 0000000..ad747d8 --- /dev/null +++ b/odb-tests/oracle/types/traits.hxx @@ -0,0 +1,192 @@ +// file : oracle/types/traits.hxx +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef TRAITS_HXX +#define TRAITS_HXX + +#include <odb/oracle/oracle-types.hxx> // datetime, interval_ym, interval_ds +#include <odb/oracle/traits.hxx> + +#include <odb/oracle/details/date.hxx> + +#include "test.hxx" // date_time, time_interval + +namespace odb +{ + namespace oracle + { + template <> + class value_traits<date_time, id_date> + { + public: + typedef date_time value_type; + typedef date_time query_type; + typedef char* image_type; + + static void + set_value (date_time& v, const char* i, bool is_null) + { + if (!is_null) + { + short y (0); + unsigned char m (0), d (0), h (0), mins (0), s (0); + + details::get_date (i, y, m, d, h, mins, s); + + v.year = y; + v.month = m; + v.day = d; + v.hour = h; + v.minute = mins; + v.second = s; + + // Oracle DATE does not support fractional seconds. + // + v.nanosecond = 0; + } + } + + static void + set_image (char* i, bool& is_null, const date_time& v) + { + is_null = false; + details::set_date (i, + static_cast<unsigned short> (v.year), + v.month, + v.day, + v.hour, + v.minute, + v.second); + } + }; + + template <> + class value_traits<date_time, id_timestamp> + { + public: + typedef date_time value_type; + typedef date_time query_type; + typedef datetime image_type; + + static void + set_value (date_time& v, const datetime& i, bool is_null) + { + if (!is_null) + { + sb2 y (0); + ub1 m (0), d (0), h (0), mins (0), s (0); + ub4 ns (0); + + i.get (y, m, d, h, mins, s, ns); + + v.year = y; + v.month = m; + v.day = d; + v.hour = h; + v.minute = mins; + v.second = s; + v.nanosecond = ns; + } + } + + static void + set_image (datetime& i, + bool& is_null, + const date_time& v) + { + is_null = false; + + i.set (static_cast<sb2> (v.year), + v.month, + v.day, + v.hour, + v.minute, + v.second, + v.nanosecond); + } + }; + + template <> + class value_traits<time_interval, id_interval_ds> + { + public: + typedef time_interval value_type; + typedef time_interval query_type; + typedef interval_ds image_type; + + static void + set_value (time_interval& v, + const interval_ds& i, + bool is_null) + { + if (!is_null) + { + sb4 d (0), h (0), m (0), s (0), ns (0); + i.get (d, h, m, s, ns); + + v.year = 0; + v.month = 0; + v.day = static_cast<unsigned char> (d); + v.hour = static_cast<unsigned char> (h); + v.minute = static_cast<unsigned char> (m); + v.second = static_cast<unsigned char> (s); + v.nanosecond = static_cast<unsigned int> (ns); + } + } + + static void + set_image (interval_ds& i, + bool& is_null, + const time_interval& v) + { + is_null = false; + + i.set (v.day, + v.hour, + v.minute, + v.second, + static_cast<sb4> (v.nanosecond)); + } + }; + + template <> + class value_traits<time_interval, id_interval_ym> + { + public: + typedef time_interval value_type; + typedef time_interval query_type; + typedef interval_ym image_type; + + static void + set_value (time_interval& v, + const interval_ym& i, + bool is_null) + { + if (!is_null) + { + sb4 y (0), m (0); + i.get (y, m); + + v.year = static_cast<unsigned short> (y); + v.month = static_cast<unsigned char> (m); + v.day = 0; + v.hour = 0; + v.minute = 0; + v.second = 0; + v.nanosecond = 0; + } + } + + static void + set_image (interval_ym& i, + bool& is_null, + const time_interval& v) + { + is_null = false; + i.set (v.year, v.month); + } + }; + } +} + +#endif // TRAITS_HXX |