diff options
Diffstat (limited to 'odb-tests/common/prepared')
-rw-r--r-- | odb-tests/common/prepared/buildfile | 43 | ||||
-rw-r--r-- | odb-tests/common/prepared/driver.cxx | 444 | ||||
-rw-r--r-- | odb-tests/common/prepared/test.hxx | 32 | ||||
-rw-r--r-- | odb-tests/common/prepared/testscript | 53 |
4 files changed, 572 insertions, 0 deletions
diff --git a/odb-tests/common/prepared/buildfile b/odb-tests/common/prepared/buildfile new file mode 100644 index 0000000..56a0074 --- /dev/null +++ b/odb-tests/common/prepared/buildfile @@ -0,0 +1,43 @@ +# file : common/prepared/buildfile +# license : GNU GPL v2; see accompanying LICENSE file + +import libodb = libodb%lib{odb} + +libs = + +for db: $databases + import libs += libodb-$db%lib{odb-$db} + +import libs += lib{common} + +exe{driver}: {hxx cxx}{* -*-odb -*-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} + +for db: $databases +{ + exe{driver}: {hxx ixx cxx}{test-odb-$db}: include = $multi + <{hxx ixx cxx}{test-odb-$db}>: 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 t_prepared_ \ + --generate-schema \ + --generate-query \ + --generate-prepared \ + --omit-unprepared + +cxx.poptions =+ "-I$out_base" "-I$src_base" + +# Testscript's run-time prerequisites. +# +exe{driver}: ../../alias{database-client}: include = adhoc diff --git a/odb-tests/common/prepared/driver.cxx b/odb-tests/common/prepared/driver.cxx new file mode 100644 index 0000000..44df651 --- /dev/null +++ b/odb-tests/common/prepared/driver.cxx @@ -0,0 +1,444 @@ +// file : common/prepared/driver.cxx +// license : GNU GPL v2; see accompanying LICENSE file + +// Test prepared query functionality. +// + +#include <memory> // std::unique_ptr +#include <utility> // std::move +#include <iostream> + +#include <odb/database.hxx> +#include <odb/transaction.hxx> + +#include <libcommon/common.hxx> + +#include "test.hxx" +#include "test-odb.hxx" + +#undef NDEBUG +#include <cassert> + +using namespace std; +using namespace odb::core; + +struct params +{ + unsigned short age; + std::string name; +}; + +static void +query_factory (const char* name, connection& c) +{ + typedef odb::query<person> query; + + unique_ptr<params> p (new params); + prepared_query<person> pq ( + c.prepare_query<person> ( + name, + query::age > query::_ref (p->age) && + query::name != query::_ref (p->name))); + c.cache_query (pq, move (p)); +} + +int +main (int argc, char* argv[]) +{ + try + { + unique_ptr<database> db (create_database (argc, argv)); + + { + person p1 ("John First", 91); + person p2 ("John Second", 81); + person p3 ("John Third", 71); + person p4 ("John Fourth", 61); + person p5 ("John Fifth", 51); + + transaction t (db->begin ()); + db->persist (p1); + db->persist (p2); + db->persist (p3); + db->persist (p4); + db->persist (p5); + t.commit (); + } + + typedef odb::query<person> query; + typedef odb::prepared_query<person> prep_query; + typedef odb::result<person> result; + + // Uncached query in the same transaction. + // + { + transaction t (db->begin ()); + + unsigned short age (90); + prep_query pq ( + db->prepare_query<person> ( + "person-age-query", + query::age > query::_ref (age))); + + for (unsigned short i (1); i < 6; ++i, age -= 10) + { + result r (pq.execute ()); + assert (size (r) == i); + } + + age = 90; + result r (pq.execute ()); + result::iterator i (r.begin ()); + assert (i != r.end () && i->name_ == "John First" && i->age_ == 91); + assert (++i == r.end ()); + + t.commit (); + } + + // Uncached query in multiple transaction. + // + { + connection_ptr c (db->connection ()); + + unsigned short age (90); + prep_query pq ( + c->prepare_query<person> ( + "person-age-query", + query::age > query::_ref (age))); + + for (unsigned short i (1); i < 6; ++i, age -= 10) + { + transaction t (c->begin ()); + + result r (pq.execute ()); + assert (size (r) == i); + + t.commit (); + } + + transaction t (c->begin ()); + + age = 90; + result r (pq.execute ()); + result::iterator i (r.begin ()); + assert (i != r.end () && i->name_ == "John First" && i->age_ == 91); + assert (++i == r.end ()); + + t.commit (); + } + + // Cached query without parameters. + // + { + for (unsigned short i (1); i < 6; ++i) + { + transaction t (db->begin ()); + + prep_query pq (db->lookup_query<person> ("person-val-age-query")); + + if (!pq) + { + assert (i == 1); + pq = db->prepare_query<person> ( + "person-val-age-query", + query::age > 90); + db->cache_query (pq); + } + else if (i == 2) + { + try + { + db->cache_query (pq); + assert (false); + } + catch (const odb::prepared_already_cached&) + { + } + } + + result r (pq.execute ()); + assert (size (r) == 1); + + t.commit (); + } + } + + // Cached query with parameters. + // + { + for (unsigned short i (1); i < 6; ++i) + { + transaction t (db->begin ()); + + unsigned short* age; + prep_query pq (db->lookup_query<person> ("person-ref-age-query", age)); + + if (!pq) + { + assert (i == 1); + + unique_ptr<unsigned short> p (new unsigned short); + age = p.get (); + pq = db->prepare_query<person> ( + "person-ref-age-query", + query::age > query::_ref (*age)); + + db->cache_query (pq, move (p)); + } + else if (i == 2) + { + // Object type mismatch. + // + try + { + db->lookup_query<int> ("person-ref-age-query", age); + assert (false); + } + catch (const odb::prepared_type_mismatch&) + { + } + + // Parameters type mismatch. + // + try + { + int* age; + db->lookup_query<person> ("person-ref-age-query", age); + assert (false); + } + catch (const odb::prepared_type_mismatch&) + { + } + } + + *age = 100 - i * 10; + result r (pq.execute ()); + assert (size (r) == i); + + t.commit (); + } + } + + // Cached query with factory. + // + { + db->query_factory ("person-params-query", &query_factory); + + for (unsigned int i (1); i < 6; ++i) + { + transaction t (db->begin ()); + + params* p; + prep_query pq (db->lookup_query<person> ("person-params-query", p)); + assert (pq); + + p->age = 100 - i * 10; + p->name = "John First"; + result r (pq.execute ()); + assert (size (r) == i - 1); + + t.commit (); + } + + db->query_factory ("person-params-query", + database::query_factory_ptr ()); + } + + // Cached query with wildcard factory. + // + { + db->query_factory ("", &query_factory); + + for (unsigned int i (1); i < 6; ++i) + { + transaction t (db->begin ()); + + params* p; + prep_query pq (db->lookup_query<person> ("person-params-query-1", p)); + assert (pq); + + p->age = 100 - i * 10; + p->name = "John First"; + result r (pq.execute ()); + assert (size (r) == i - 1); + + t.commit (); + } + + db->query_factory ("", database::query_factory_ptr ()); + } + + // Cached query with lambda factory. + // + { + db->query_factory ( + "person-params-query-2", + [] (const char* name, connection& c) + { + typedef odb::query<person> query; + + unique_ptr<params> p (new params); + prepared_query<person> pq ( + c.prepare_query<person> ( + name, + query::age > query::_ref (p->age) && + query::name != query::_ref (p->name))); + c.cache_query (pq, move (p)); + }); + + for (unsigned int i (1); i < 6; ++i) + { + transaction t (db->begin ()); + + params* p; + prep_query pq (db->lookup_query<person> ("person-params-query-2", p)); + assert (pq); + + p->age = 100 - i * 10; + p->name = "John First"; + result r (pq.execute ()); + assert (size (r) == i - 1); + + t.commit (); + } + + db->query_factory ("person-params-query-2", + database::query_factory_ptr ()); + } + + // Cached query with lambda factory using closure. Forces nonoptimized + // representation of std::function. + // + { + const std::string person_name ("John First"); + + db->query_factory ( + "person-params-query-3", + [person_name] (const char* name, connection& c) + { + typedef odb::query<person> query; + + prepared_query<person> pq ( + c.prepare_query<person> ( + name, + query::age > 50 && query::name != person_name)); + c.cache_query (pq); + }); + + { + transaction t (db->begin ()); + + prep_query pq (db->lookup_query<person> ("person-params-query-3")); + assert (pq); + + result r (pq.execute ()); + assert (size (r) == 4); + + t.commit (); + } + + db->query_factory ("person-params-query-3", nullptr); + } + + // View prepared query. + // + { + typedef odb::query<person_view> query; + typedef odb::prepared_query<person_view> prep_query; + typedef odb::result<person_view> result; + + transaction t (db->begin ()); + + unsigned short age (90); + prep_query pq ( + db->prepare_query<person_view> ( + "person-view-age-query", + query::age > query::_ref (age))); + + for (unsigned short i (1); i < 6; ++i, age -= 10) + { + result r (pq.execute ()); + assert (size (r) == i); + } + + age = 90; + result r (pq.execute ()); + result::iterator i (r.begin ()); + assert (i != r.end () && i->name == "John First" && i->age == 91); + assert (++i == r.end ()); + + t.commit (); + } + + // By-ref parameter image growth. + // + { + transaction t (db->begin ()); + + string name; + prep_query pq ( + db->prepare_query<person> ( + "person-name-query", + query::name != query::_ref (name))); + + { + name = "John First"; + result r (pq.execute ()); + assert (size (r) == 4); + } + + { + name.assign (2048, 'x'); + result r (pq.execute ()); + assert (size (r) == 5); + } + + t.commit (); + } + + // Test execute_one() and execute_value(). + // + { + transaction t (db->begin ()); + + person p ("John Doe", 23); + db->persist (p); + + prep_query pq1 ( + db->prepare_query<person> ("query-1", query::id == p.id_)); + prep_query pq0 ( + db->prepare_query<person> ("query-0", query::id == p.id_ + 1)); + + { + unique_ptr<person> p (pq1.execute_one ()); + assert (p.get () != 0 && p->name_ == "John Doe"); + } + + { + unique_ptr<person> p (pq0.execute_one ()); + assert (p.get () == 0); + } + + { + person p; + assert (pq1.execute_one (p) && p.name_ == "John Doe"); + } + + { + person p ("", 0); + assert (!pq0.execute_one (p) && + p.id_ == 0 && p.name_.empty () && p.age_ == 0); + } + + { + person p (pq1.execute_value ()); + assert (p.name_ == "John Doe"); + } + } + } + catch (const odb::exception& e) + { + cerr << e.what () << endl; + return 1; + } +} diff --git a/odb-tests/common/prepared/test.hxx b/odb-tests/common/prepared/test.hxx new file mode 100644 index 0000000..db16e67 --- /dev/null +++ b/odb-tests/common/prepared/test.hxx @@ -0,0 +1,32 @@ +// file : common/prepared/test.hxx +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef TEST_HXX +#define TEST_HXX + +#include <string> + +#include <odb/core.hxx> + +#pragma db object +struct person +{ + person (): id_ (0) {} + person (const std::string& name, unsigned short age) + : id_ (0), name_ (name), age_ (age) {} + + #pragma db id auto + unsigned long id_; + + std::string name_; + unsigned short age_; +}; + +#pragma db view object(person) +struct person_view +{ + std::string name; + unsigned short age; +}; + +#endif // TEST_HXX diff --git a/odb-tests/common/prepared/testscript b/odb-tests/common/prepared/testscript new file mode 100644 index 0000000..d378a79 --- /dev/null +++ b/odb-tests/common/prepared/testscript @@ -0,0 +1,53 @@ +# file : common/prepared/testscript +# license : GNU GPL v2; see accompanying LICENSE file + +.include ../../database-options.testscript + +: mysql +: +if $mysql +{ + .include ../../mysql.testscript + + $create_schema; + $* +} + +: sqlite +: +if $sqlite +{ + .include ../../sqlite.testscript + + $* +} + +: pgsql +: +if $pgsql +{ + .include ../../pgsql.testscript + + $create_schema; + $* +} + +: oracle +: +if $oracle +{ + .include ../../oracle.testscript + + $create_schema; + $* +} + +: mssql +: +if $mssql +{ + .include ../../mssql.testscript + + $create_schema; + $* +} |