// file : common/prepared/driver.cxx // license : GNU GPL v2; see accompanying LICENSE file // Test prepared query functionality. // #include // std::unique_ptr #include // std::move #include #include #include #include #include "test.hxx" #include "test-odb.hxx" #undef NDEBUG #include 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 query; unique_ptr p (new params); prepared_query pq ( c.prepare_query ( 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 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 query; typedef odb::prepared_query prep_query; typedef odb::result result; // Uncached query in the same transaction. // { transaction t (db->begin ()); unsigned short age (90); prep_query pq ( db->prepare_query ( "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-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-val-age-query")); if (!pq) { assert (i == 1); pq = db->prepare_query ( "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-ref-age-query", age)); if (!pq) { assert (i == 1); unique_ptr p (new unsigned short); age = p.get (); pq = db->prepare_query ( "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 ("person-ref-age-query", age); assert (false); } catch (const odb::prepared_type_mismatch&) { } // Parameters type mismatch. // try { int* age; db->lookup_query ("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-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-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 query; unique_ptr p (new params); prepared_query pq ( c.prepare_query ( 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-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 query; prepared_query pq ( c.prepare_query ( name, query::age > 50 && query::name != person_name)); c.cache_query (pq); }); { transaction t (db->begin ()); prep_query pq (db->lookup_query ("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 query; typedef odb::prepared_query prep_query; typedef odb::result result; transaction t (db->begin ()); unsigned short age (90); prep_query pq ( db->prepare_query ( "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-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 ("query-1", query::id == p.id_)); prep_query pq0 ( db->prepare_query ("query-0", query::id == p.id_ + 1)); { unique_ptr p (pq1.execute_one ()); assert (p.get () != 0 && p->name_ == "John Doe"); } { unique_ptr 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; } }