aboutsummaryrefslogtreecommitdiff
path: root/common/polymorphism/driver.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'common/polymorphism/driver.cxx')
-rw-r--r--common/polymorphism/driver.cxx1830
1 files changed, 1830 insertions, 0 deletions
diff --git a/common/polymorphism/driver.cxx b/common/polymorphism/driver.cxx
new file mode 100644
index 0000000..efda095
--- /dev/null
+++ b/common/polymorphism/driver.cxx
@@ -0,0 +1,1830 @@
+// file : common/polymorphism/driver.cxx
+// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+// Test polymorphic object inheritance.
+//
+
+#include <memory> // std::auto_ptr
+#include <cassert>
+#include <iostream>
+
+#include <odb/database.hxx>
+#include <odb/transaction.hxx>
+
+#include <common/common.hxx>
+
+#include "test.hxx"
+#include "test-odb.hxx"
+
+using namespace std;
+using namespace odb::core;
+
+const char* events[] =
+{
+ "pre_persist",
+ "post_persist",
+ "pre_load",
+ "post_load",
+ "pre_update",
+ "post_update",
+ "pre_erase",
+ "post_erase"
+};
+
+namespace test6
+{
+ void base::
+ db_callback (callback_event e, database&)
+ {
+ cout << "base " << events[e] << " " << id << endl;
+ }
+
+ void base::
+ db_callback (callback_event e, database&) const
+ {
+ cout << "base " << events[e] << " " << id << " const" << endl;
+ }
+
+ void derived::
+ db_callback (callback_event e, database&) const
+ {
+ cout << "derived " << events[e] << " " << id << " const" << endl;
+ }
+}
+
+int
+main (int argc, char* argv[])
+{
+ try
+ {
+ auto_ptr<database> db (create_database (argc, argv));
+
+ // Test 1: basic polymorphism functionality.
+ //
+ {
+ using namespace test1;
+
+ root r (1, 1);
+ base b (2, 2, "bbb");
+ derived d (3, 3, "ddd");
+
+ r.strs.push_back ("a");
+ r.strs.push_back ("aa");
+ r.strs.push_back ("aaa");
+
+ b.nums.push_back (21);
+ b.nums.push_back (22);
+ b.nums.push_back (23);
+ b.strs.push_back ("b");
+ b.strs.push_back ("bb");
+ b.strs.push_back ("bbb");
+
+ d.nums.push_back (31);
+ d.nums.push_back (32);
+ d.nums.push_back (33);
+ d.strs.push_back ("d");
+ d.strs.push_back ("dd");
+ d.strs.push_back ("ddd");
+
+ {
+ transaction t (db->begin ());
+
+ // Static persist.
+ //
+ db->persist (r);
+ db->persist (b);
+
+ // Dynamic persist.
+ //
+ root& r (d);
+ db->persist (r);
+
+ t.commit ();
+ }
+
+ // Static load.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<root> pr (db->load<root> (r.id));
+ auto_ptr<base> pb (db->load<base> (b.id));
+ auto_ptr<derived> pd (db->load<derived> (d.id));
+ t.commit ();
+
+ assert (*pr == r);
+ assert (*pb == b);
+ assert (*pd == d);
+ }
+
+ // Dynamic load.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<root> pb (db->load<root> (b.id));
+ auto_ptr<root> pd1 (db->load<root> (d.id));
+ auto_ptr<base> pd2 (db->load<base> (d.id));
+ t.commit ();
+
+ assert (*pb == b);
+ assert (*pd1 == d);
+ assert (*pd2 == d);
+ }
+
+ // Invalid load.
+ //
+ {
+ transaction t (db->begin ());
+
+ try
+ {
+ auto_ptr<base> p (db->load<base> (r.id));
+ assert (false);
+ }
+ catch (const object_not_persistent&) {}
+
+ try
+ {
+ auto_ptr<derived> p (db->load<derived> (b.id));
+ assert (false);
+ }
+ catch (const object_not_persistent&) {}
+
+ t.commit ();
+ }
+
+ // Static load into existing instance.
+ //
+ {
+ transaction t (db->begin ());
+ root r1;
+ db->load (r.id, r1);
+ base b1;
+ db->load (b.id, b1);
+ derived d1;
+ db->load (d.id, d1);
+ t.commit ();
+
+ assert (r1 == r);
+ assert (b1 == b);
+ assert (d1 == d);
+ }
+
+ // Dynamic load into existing instance.
+ //
+ {
+ transaction t (db->begin ());
+ base b1;
+ db->load (b.id, static_cast<root&> (b1));
+ derived d1;
+ db->load (d.id, static_cast<base&> (d1));
+ t.commit ();
+
+ assert (b1 == b);
+ assert (d1 == d);
+ }
+
+ // Invalid load into existing instance.
+ //
+ {
+ transaction t (db->begin ());
+
+ try
+ {
+ base b;
+ db->load (r.id, static_cast<root&> (b));
+ assert (false);
+ }
+ catch (const object_not_persistent&) {}
+
+ try
+ {
+ derived d;
+ db->load (b.id, static_cast<base&> (d));
+ assert (false);
+ }
+ catch (const object_not_persistent&) {}
+
+ t.commit ();
+ }
+
+ // Slicing load.
+ //
+ {
+ transaction t (db->begin ());
+ root b1;
+ db->load (b.id, b1);
+ base d1;
+ db->load (d.id, d1);
+ t.commit ();
+
+ assert (b1 == static_cast<root> (b));
+ assert (d1 == static_cast<base> (d));
+ }
+
+ // Static reload.
+ //
+ {
+ transaction t (db->begin ());
+ root r1;
+ r1.id = r.id;
+ db->reload (r1);
+ base b1;
+ b1.id = b.id;
+ db->reload (b1);
+ derived d1;
+ d1.id = d.id;
+ db->reload (d1);
+ t.commit ();
+
+ assert (r1 == r);
+ assert (b1 == b);
+ assert (d1 == d);
+ }
+
+ // Dynamic reload.
+ //
+ {
+ transaction t (db->begin ());
+ base b1;
+ b1.id = b.id;
+ db->reload (static_cast<root&> (b1));
+ derived d1;
+ d1.id = d.id;
+ db->reload (static_cast<base&> (d1));
+ t.commit ();
+
+ assert (b1 == b);
+ assert (d1 == d);
+ }
+
+ // Invalid reload.
+ //
+ {
+ transaction t (db->begin ());
+
+ try
+ {
+ base b;
+ b.id = r.id;
+ db->reload (static_cast<root&> (b));
+ assert (false);
+ }
+ catch (const object_not_persistent&) {}
+
+ try
+ {
+ derived d;
+ d.id = b.id;
+ db->reload (static_cast<base&> (d));
+ assert (false);
+ }
+ catch (const object_not_persistent&) {}
+
+ t.commit ();
+ }
+
+ // Slicing reload.
+ //
+ {
+ transaction t (db->begin ());
+ root b1;
+ b1.id = b.id;
+ db->reload (b1);
+ base d1;
+ d1.id = d.id;
+ db->reload (d1);
+ t.commit ();
+
+ assert (b1 == static_cast<root> (b));
+ assert (d1 == static_cast<base> (d));
+ }
+
+ // Query.
+ //
+ {
+ typedef odb::query<root> root_query;
+ typedef odb::result<root> root_result;
+
+ typedef odb::query<base> base_query;
+ typedef odb::result<base> base_result;
+
+ typedef odb::query<derived> derived_query;
+ typedef odb::result<derived> derived_result;
+
+ transaction t (db->begin ());
+
+ // Test loading via root.
+ //
+ {
+ root_result qr (db->query<root> ("ORDER BY" + root_query::id));
+ root_result::iterator i (qr.begin ()), e (qr.end ());
+
+ assert (i != e && *i == r);
+ assert (++i != e && *i == b);
+ assert (++i != e && *i == d);
+ assert (++i == e);
+ }
+
+ // Test loading via base.
+ //
+ {
+ base_result qr (db->query<base> ("ORDER BY" + base_query::id));
+ base_result::iterator i (qr.begin ()), e (qr.end ());
+
+ assert (i != e && *i == b);
+ assert (++i != e && *i == d);
+ assert (++i == e);
+ }
+
+ // Test loading via derived.
+ //
+ {
+ derived_result qr (db->query<derived> ());
+ derived_result::iterator i (qr.begin ()), e (qr.end ());
+
+ assert (i != e && *i == d);
+ assert (++i == e);
+ }
+
+ // Test loading into an existing instance.
+ //
+ {
+ root_result qr (db->query<root> ());
+
+ unsigned short mask (0);
+
+ for (root_result::iterator i (qr.begin ()); i != qr.end (); ++i)
+ {
+ string ds (i.discriminator ());
+
+ if (ds == "test1::root")
+ {
+ root r1;
+ i.load (r1);
+ assert (r1 == r);
+ mask |= 1;
+ }
+ else if (ds == "test1::base")
+ {
+ base b1;
+ i.load (b1);
+ assert (b1 == b);
+ mask |= 2;
+ }
+ else if (ds == "test1::derived")
+ {
+ derived d1;
+ i.load (d1);
+ assert (d1 == d);
+ mask |= 4;
+ }
+ else
+ assert (false);
+ }
+
+ assert (mask == 7);
+ }
+
+ // Test query conditions with columns from multiple tables.
+ //
+ {
+ base_result qr (
+ db->query<base> (
+ base_query::num == 3 && base_query::str == "ddd"));
+
+ base_result::iterator i (qr.begin ()), e (qr.end ());
+
+ assert (i != e && *i == d);
+ assert (++i == e);
+ }
+
+ // Test discriminator access.
+ //
+ {
+ base_result qr (db->query<base> (base_query::id == 3));
+ base_result::iterator i (qr.begin ()), e (qr.end ());
+
+ assert (i != e && i.discriminator () == "test1::derived");
+ assert (++i == e);
+ }
+
+ // Test loading of an object from the same hierarchy during
+ // query result iteration (tests image copying via change
+ // callbacks in some databases).
+ //
+ {
+ base_result qr (db->query<base> ());
+
+ unsigned short mask (0);
+
+ for (base_result::iterator i (qr.begin ()); i != qr.end (); ++i)
+ {
+ string ds (i.discriminator ());
+
+ if (ds == "test1::base")
+ {
+ auto_ptr<derived> d1 (db->load<derived> (d.id));
+ assert (*d1 == d);
+ assert (*i == b);
+ mask |= 1;
+ }
+ else if (ds == "test1::derived")
+ {
+ auto_ptr<base> b1 (db->load<base> (b.id));
+ assert (*b1 == b);
+ assert (*i == d);
+ mask |= 2;
+ }
+ }
+
+ assert (mask == 3);
+ }
+
+ t.commit ();
+ }
+
+ // Views.
+ //
+ {
+ typedef odb::query<root_view> root_query;
+ typedef odb::result<root_view> root_result;
+
+ typedef odb::query<base_view> base_query;
+ typedef odb::result<base_view> base_result;
+
+ typedef odb::query<derived_view> derived_query;
+ typedef odb::result<derived_view> derived_result;
+
+ transaction t (db->begin ());
+
+ // root
+ //
+ {
+ root_result qr (db->query<root_view> ("ORDER BY" + root_query::id));
+ root_result::iterator i (qr.begin ()), e (qr.end ());
+
+ assert (i != e && i->typeid_ == "test1::root" && i->num == r.num);
+ assert (++i != e && i->typeid_ == "test1::base" && i->num == b.num);
+ assert (++i != e && i->typeid_ == "test1::derived" && i->num == d.num);
+ assert (++i == e);
+ }
+
+ // base
+ //
+ {
+ base_result qr (db->query<base_view> ("ORDER BY" + base_query::id));
+ base_result::iterator i (qr.begin ()), e (qr.end ());
+
+ assert (i != e &&
+ i->id == b.id && i->num == b.num && i->str == b.str);
+ assert (++i != e &&
+ i->id == d.id && i->num == d.num && i->str == d.str);
+ assert (++i == e);
+ }
+
+ // derived
+ //
+ {
+ derived_result qr (db->query<derived_view> ());
+ derived_result::iterator i (qr.begin ()), e (qr.end ());
+
+ assert (i != e &&
+ i->num == d.num && i->str == d.str &&
+ i->dnum == d.dnum && i->dstr == d.dstr);
+ assert (++i == e);
+ }
+
+ t.commit ();
+ }
+
+ // Update.
+ //
+ r.num++;
+ r.strs.push_back ("aaaa");
+
+ b.num++;
+ b.str += "b";
+ b.nums.push_back (24);
+ b.strs.push_back ("bbbb");
+
+ d.num++;
+ d.str += "d";
+ d.dnum++;
+ d.dstr += "d";
+ d.nums.push_back (34);
+ d.strs.push_back ("dddd");
+
+ {
+ transaction t (db->begin ());
+
+ // Static update.
+ //
+ db->update (r);
+ db->update (b);
+
+ // Dynamic update.
+ //
+ root& r (d);
+ db->update (r);
+
+ t.commit ();
+ }
+
+ // Verify update.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<root> pr (db->load<root> (r.id));
+ auto_ptr<base> pb (db->load<base> (b.id));
+ auto_ptr<derived> pd (db->load<derived> (d.id));
+ t.commit ();
+
+ assert (*pr == r);
+ assert (*pb == b);
+ assert (*pd == d);
+ }
+
+ // Invalid erase via id.
+ //
+ {
+ transaction t (db->begin ());
+
+ try
+ {
+ db->erase<base> (r.id);
+ assert (false);
+ }
+ catch (const object_not_persistent&) {}
+
+ try
+ {
+ db->erase<derived> (b.id);
+ assert (false);
+ }
+ catch (const object_not_persistent&) {}
+
+ t.commit ();
+ }
+
+ // Static erase via id.
+ //
+ {
+ transaction t (db->begin ());
+ db->erase<root> (r.id);
+ db->erase<base> (b.id);
+ t.commit ();
+ }
+
+ // Dynamic erase via id.
+ //
+ {
+ transaction t (db->begin ());
+ db->erase<root> (d.id);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->persist (r);
+ db->persist (b);
+ db->persist (d);
+ t.commit ();
+ }
+
+ // Static erase via object.
+ //
+ {
+ transaction t (db->begin ());
+ db->erase (r);
+ db->erase (b);
+ t.commit ();
+ }
+
+ // Dynamic erase via object.
+ //
+ {
+ const root& r (d);
+ transaction t (db->begin ());
+ db->erase (r);
+ t.commit ();
+ }
+ }
+
+ // Test 2: inverse object pointers in polymorhic bases.
+ //
+ {
+ using namespace test2;
+
+ derived d (1, "d", 1);
+ root_pointer rp (&d);
+ base_pointer bp (&d);
+
+ {
+ transaction t (db->begin ());
+ db->persist (rp);
+ db->persist (bp);
+
+ d.rp.reset (*db, &rp);
+ d.bp.reset (*db, &bp);
+
+ db->persist (d);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<derived> pd (db->load<derived> (d.id));
+ auto_ptr<base> pb (db->load<base> (d.id));
+ auto_ptr<root> pr (db->load<root> (d.id));
+ t.commit ();
+
+ assert (pd->rp.object_id<root_pointer> () == rp.id &&
+ pd->bp.object_id<base_pointer> () == bp.id);
+
+ derived* p (dynamic_cast<derived*> (pb.get ()));
+ assert (p != 0 &&
+ p->rp.object_id<root_pointer> () == rp.id &&
+ p->bp.object_id<base_pointer> () == bp.id);
+
+ p = dynamic_cast<derived*> (pr.get ());
+ assert (p != 0 &&
+ p->rp.object_id<root_pointer> () == rp.id &&
+ p->bp.object_id<base_pointer> () == bp.id);
+ }
+
+ // Query.
+ //
+ {
+ typedef odb::query<base> base_query;
+ typedef odb::result<base> base_result;
+
+ transaction t (db->begin ());
+
+ // Test query conditions with columns in pointed-to objects from
+ // multiple tables.
+ //
+ {
+ base_result qr (
+ db->query<base> (
+ base_query::rp->id == rp.id &&
+ base_query::bp->id == bp.id));
+
+ base_result::iterator i (qr.begin ()), e (qr.end ());
+
+ assert (i != e && i.discriminator () == "test2::derived");
+ assert (++i == e);
+ }
+
+ t.commit ();
+ }
+
+ // Views.
+ //
+ {
+ typedef odb::query<root_view> root_query;
+ typedef odb::result<root_view> root_result;
+
+ typedef odb::query<base_view> base_query;
+ typedef odb::result<base_view> base_result;
+
+ transaction t (db->begin ());
+
+ // root
+ //
+ {
+ root_result qr (db->query<root_view> ());
+ root_result::iterator i (qr.begin ()), e (qr.end ());
+
+ assert (i != e && i->rp_id == rp.id && i->r_id == d.id);
+ assert (++i == e);
+ }
+
+ // base
+ //
+ {
+ base_result qr (db->query<base_view> ());
+ base_result::iterator i (qr.begin ()), e (qr.end ());
+
+ assert (i != e &&
+ i->bp_id == bp.id && i->b_id == d.id && i->str == d.str);
+ assert (++i == e);
+ }
+
+ t.commit ();
+ }
+ }
+
+ // Test 3: delayed loading.
+ //
+ {
+ using namespace test3;
+
+ base b1 (21, 21);
+ base b2 (22, 22);
+ base b3 (23, 23);
+
+ derived d1 (31, 31, "d");
+ derived d2 (32, 32, "dd");
+ derived d3 (33, 33, "ddd");
+
+ b1.rptr = new root (1);
+ b2.rptr = new base (2, 2);
+ b3.rptr = new derived (3, 3, "b3");
+
+ d1.rptr = new root (4);
+ d2.rptr = new base (5, 5);
+ d3.rptr = new derived (6, 6, "d3");
+
+ d2.bptr = new base (7, 7);
+ d3.bptr = new derived (8, 8, "d3b");
+
+ {
+ transaction t (db->begin ());
+ db->persist (b1);
+ db->persist (b2);
+ db->persist (b3);
+
+ db->persist (d1);
+ db->persist (d2);
+ db->persist (d3);
+
+ db->persist (b1.rptr);
+ db->persist (b2.rptr);
+ db->persist (b3.rptr);
+
+ db->persist (d1.rptr);
+ db->persist (d2.rptr);
+ db->persist (d3.rptr);
+
+ db->persist (d2.bptr);
+ db->persist (d3.bptr);
+
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+
+ {
+ auto_ptr<base> p1 (db->load<base> (b1.id));
+ auto_ptr<base> p2 (db->load<base> (b2.id));
+ auto_ptr<root> p3 (db->load<root> (b3.id));
+ assert (*p1 == b1);
+ assert (*p2 == b2);
+ assert (*p3 == b3);
+ }
+
+ {
+ auto_ptr<derived> p1 (db->load<derived> (d1.id));
+ auto_ptr<base> p2 (db->load<base> (d2.id));
+ auto_ptr<root> p3 (db->load<root> (d3.id));
+ assert (*p1 == d1);
+ assert (*p2 == d2);
+ assert (*p3 == d3);
+ }
+
+ t.commit ();
+ }
+
+ // Query.
+ //
+ {
+ typedef odb::query<derived> derived_query;
+ typedef odb::result<derived> derived_result;
+
+ transaction t (db->begin ());
+
+ // Test query conditions with columns in pointed-to objects from
+ // multiple tables.
+ //
+ {
+ derived_result qr (
+ db->query<derived> (
+ derived_query::rptr->id == 6 &&
+ derived_query::bptr->id == 8 &&
+ derived_query::bptr->num == 8));
+
+ derived_result::iterator i (qr.begin ()), e (qr.end ());
+
+ assert (i != e && *i == d3);
+ assert (++i == e);
+ }
+
+ t.commit ();
+ }
+
+ // Views.
+ //
+ {
+ typedef odb::query<base_view> base_query;
+ typedef odb::result<base_view> base_result;
+
+ typedef odb::query<derived_view> derived_query;
+ typedef odb::result<derived_view> derived_result;
+
+ typedef odb::query<root_view> root_query;
+ typedef odb::result<root_view> root_result;
+
+ transaction t (db->begin ());
+
+ // base
+ //
+ {
+ base_result qr (
+ db->query<base_view> (
+ base_query::base::num == b2.num &&
+ base_query::base::id == b2.id &&
+ base_query::r::id == b2.rptr->id));
+
+ base_result::iterator i (qr.begin ()), e (qr.end ());
+
+ assert (i != e &&
+ i->b_id == b2.id &&
+ i->r_id == b2.rptr->id &&
+ i->num == b2.num);
+ assert (++i == e);
+ }
+
+ // derived
+ //
+ {
+ derived_result qr (
+ db->query<derived_view> (
+ derived_query::d::str == d3.str &&
+ derived_query::d::num == d3.num &&
+ derived_query::b::num == d3.bptr->num &&
+ derived_query::d::id == d3.id &&
+ derived_query::b::id == d3.bptr->id &&
+ derived_query::r::id == d3.rptr->id));
+
+ derived_result::iterator i (qr.begin ()), e (qr.end ());
+
+ assert (i != e &&
+ i->d_id == d3.id &&
+ i->b_id == d3.bptr->id &&
+ i->r_id == d3.rptr->id &&
+ i->d_num == d3.num &&
+ i->b_num == d3.bptr->num &&
+ i->str == d3.str);
+ assert (++i == e);
+ }
+
+ // root
+ //
+ {
+ root_result qr (
+ db->query<root_view> (
+ root_query::r::id.in (b2.rptr->id, d2.rptr->id)));
+
+ root_result::iterator i (qr.begin ()), e (qr.end ());
+
+ assert (i != e &&
+ i->r_id == d2.rptr->id &&
+ i->d_id == d2.id &&
+ i->str == d2.str);
+ assert (++i == e);
+ }
+
+ t.commit ();
+ }
+ }
+
+ // Test 4: views.
+ //
+ {
+ using namespace test4;
+
+ base1 b1 (21, 1);
+
+ root2 r2 (11, 0);
+ base2 b2 (21, 1, "abc");
+
+ {
+ transaction t (db->begin ());
+ db->persist (b1);
+ db->persist (r2);
+ db->persist (b2);
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<view1> query;
+ typedef odb::result<view1> result;
+
+ transaction t (db->begin ());
+
+ {
+ result qr (
+ db->query<view1> (
+ query::base1::num == b1.num));
+
+ result::iterator i (qr.begin ()), e (qr.end ());
+
+ assert (i != e && i->str == "abc");
+ assert (++i == e);
+ }
+
+ t.commit ();
+ }
+
+ {
+ typedef odb::query<view2> query;
+ typedef odb::result<view2> result;
+
+ transaction t (db->begin ());
+
+ {
+ result qr (db->query<view2> ());
+ result::iterator i (qr.begin ()), e (qr.end ());
+
+ assert (i != e && i->min_num == 1);
+ assert (++i == e);
+ }
+
+ t.commit ();
+ }
+ }
+
+ // Test 5: polymorphism and optimistic concurrency.
+ //
+ {
+ using namespace test5;
+
+ root r (1, 1);
+ base b (2, 2, "bbb");
+ derived d (3, 3, "ddd");
+
+ r.strs.push_back ("a");
+ r.strs.push_back ("aa");
+ r.strs.push_back ("aaa");
+
+ b.nums.push_back (21);
+ b.nums.push_back (22);
+ b.nums.push_back (23);
+ b.strs.push_back ("b");
+ b.strs.push_back ("bb");
+ b.strs.push_back ("bbb");
+
+ d.nums.push_back (31);
+ d.nums.push_back (32);
+ d.nums.push_back (33);
+ d.strs.push_back ("d");
+ d.strs.push_back ("dd");
+ d.strs.push_back ("ddd");
+
+ {
+ transaction t (db->begin ());
+ db->persist (r);
+ db->persist (b);
+ db->persist (d);
+ t.commit ();
+ }
+
+ // Update.
+ //
+ {
+ transaction t (db->begin ());
+
+ // Root.
+ //
+ {
+ auto_ptr<root> p (db->load<root> (r.id));
+
+ r.num++;
+ r.strs.push_back ("aaaa");
+ db->update (r);
+
+ p->num--;
+ p->strs.pop_back ();
+ try
+ {
+ db->update (p);
+ assert (false);
+ }
+ catch (const odb::object_changed&) {}
+
+ // Make sure the object is intact.
+ //
+ db->reload (p);
+ assert (r == *p);
+ }
+
+ // Base.
+ //
+ {
+ auto_ptr<base> p (db->load<base> (b.id));
+
+ b.num++;
+ b.str += "b";
+ b.strs.push_back ("bbbb");
+ b.nums.push_back (24);
+ db->update (b);
+
+ p->num--;
+ p->str += "B";
+ p->strs.pop_back ();
+ p->nums.pop_back ();
+ try
+ {
+ db->update (p);
+ assert (false);
+ }
+ catch (const odb::object_changed&) {}
+
+ // Make sure the object is intact.
+ //
+ db->reload (p);
+ assert (b == *p);
+ }
+
+ // Derived.
+ //
+ {
+ auto_ptr<root> p (db->load<root> (d.id)); // Via root.
+
+ d.num++;
+ d.str += "d";
+ d.strs.push_back ("dddd");
+ d.nums.push_back (24);
+ d.dnum++;
+ d.dstr += "d";
+ db->update (d);
+
+ derived& d1 (static_cast<derived&> (*p));
+ d1.num--;
+ d1.str += "D";
+ d1.strs.pop_back ();
+ d1.nums.pop_back ();
+ d1.dnum--;
+ d1.dstr += "D";
+ try
+ {
+ db->update (p);
+ assert (false);
+ }
+ catch (const odb::object_changed&) {}
+
+ // Make sure the object is intact.
+ //
+ db->reload (p);
+ assert (d == *p);
+ }
+
+ t.commit ();
+ }
+
+ // Reload.
+ //
+ {
+ transaction t (db->begin ());
+
+ // Make sure reload doesn't modify the object if the versions
+ // match.
+ //
+ derived d1 (d);
+ d1.num++;
+ d1.str += "d";
+ d1.strs.push_back ("dddd");
+ d1.nums.push_back (24);
+ d1.dnum++;
+ d1.dstr += "d";
+ derived d2 (d1);
+
+ db->reload (d1);
+ assert (d1 == d2);
+
+ t.commit ();
+ }
+
+ // Erase.
+ //
+ {
+ transaction t (db->begin ());
+
+ // Root.
+ //
+ {
+ auto_ptr<root> p (db->load<root> (r.id));
+
+ r.num++;
+ r.strs.push_back ("aaaaa");
+ db->update (r);
+
+ try
+ {
+ db->erase (p);
+ assert (false);
+ }
+ catch (const odb::object_changed&) {}
+
+ db->reload (p);
+ db->erase (p);
+ }
+
+ // Base.
+ //
+ {
+ auto_ptr<base> p (db->load<base> (b.id));
+
+ b.num++;
+ b.str += "b";
+ b.strs.push_back ("bbbb");
+ b.nums.push_back (24);
+ db->update (b);
+
+ try
+ {
+ db->erase (p);
+ assert (false);
+ }
+ catch (const odb::object_changed&) {}
+
+ db->reload (p);
+ db->erase (p);
+ }
+
+ // Derived.
+ //
+ {
+ auto_ptr<root> p (db->load<root> (d.id)); // Via root.
+
+ d.num++;
+ d.str += "d";
+ d.strs.push_back ("dddd");
+ d.nums.push_back (24);
+ d.dnum++;
+ d.dstr += "d";
+ db->update (d);
+
+ try
+ {
+ db->erase (p);
+ assert (false);
+ }
+ catch (const odb::object_changed&) {}
+
+ db->reload (p);
+ db->erase (p);
+ }
+
+ // Try to update non-existent object.
+ //
+ {
+ try
+ {
+ db->update (d);
+ assert (false);
+ }
+ catch (const odb::object_changed&) {}
+ }
+
+ // Try to erase non-existent object.
+ //
+ {
+ try
+ {
+ db->erase (d);
+ assert (false);
+ }
+ catch (const odb::object_changed&) {}
+ }
+
+ t.commit ();
+ }
+ }
+
+ // Test 6: polymorphism and callbacks.
+ //
+ {
+ using namespace test6;
+
+ base b (1, 1, "bbb");
+ auto_ptr<base> d (new derived (2, 2, "ddd"));
+
+ // Persist.
+ //
+ {
+ transaction t (db->begin ());
+ db->persist (b);
+ db->persist (d);
+ t.commit ();
+ }
+
+ // Load.
+ //
+ {
+ transaction t (db->begin ());
+
+ auto_ptr<base> pb (db->load<base> (b.id));
+ auto_ptr<root> pd (db->load<root> (d->id));
+
+ db->load (b.id, *pb);
+ db->load (d->id, *pd);
+
+ db->reload (*pb);
+ db->reload (*pd);
+
+ t.commit ();
+ }
+
+ // Update.
+ //
+ {
+ b.num++;
+ d->num++;
+
+ transaction t (db->begin ());
+ db->update (b);
+ db->update (d);
+ t.commit ();
+ }
+
+ // Query.
+ //
+ {
+ typedef odb::query<base> query;
+ typedef odb::result<base> result;
+
+ transaction t (db->begin ());
+
+ result r (db->query<base> ("ORDER BY" + query::id));
+ for (result::iterator i (r.begin ()); i != r.end (); ++i)
+ *i;
+
+ t.commit ();
+ }
+
+ // Erase.
+ //
+ {
+ transaction t (db->begin ());
+ db->erase (b);
+ db->erase (d);
+ t.commit ();
+ }
+
+ // Recursive (delayed) loading.
+ //
+ {
+ derived d (3, 3, "dddd");
+ d.ptr.reset (new derived (4, 4, "ddddd"));
+
+ {
+ transaction t (db->begin ());
+ db->persist (d);
+ db->persist (d.ptr);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<root> p (db->load<root> (d.id));
+ t.commit ();
+ }
+ }
+ }
+
+ // Test 7: polymorphism and object cache (session).
+ //
+#if defined(HAVE_CXX11) || defined(HAVE_TR1_MEMORY)
+ {
+ using namespace test7;
+
+ shared_ptr<root> r (new root (1, 1));
+ shared_ptr<base> b (new base (2, 2, "b"));
+ shared_ptr<root> d (new derived (3, 3, "d"));
+
+ // Persist.
+ //
+ {
+ session s;
+
+ {
+ transaction t (db->begin ());
+ db->persist (r);
+ db->persist (b);
+ db->persist (d);
+ t.commit ();
+ }
+
+ assert (db->load<root> (r->id) == r);
+ assert (db->load<base> (b->id) == b);
+ assert (db->load<root> (d->id) == d);
+ }
+
+ // Load.
+ //
+ {
+ session s;
+
+ transaction t (db->begin ());
+ shared_ptr<root> r1 (db->load<root> (r->id));
+ shared_ptr<base> b1 (db->load<base> (b->id));
+ shared_ptr<derived> d1 (db->load<derived> (d->id));
+ t.commit ();
+
+ assert (db->load<root> (r->id) == r1);
+ assert (db->load<base> (b->id) == b1);
+ assert (db->load<root> (d->id) == d1);
+
+ assert (!db->find<derived> (b->id));
+ }
+
+ // Query.
+ //
+ {
+ typedef odb::query<root> query;
+ typedef odb::result<root> result;
+
+ session s;
+
+ transaction t (db->begin ());
+ shared_ptr<root> r1 (db->load<root> (r->id));
+ shared_ptr<base> b1 (db->load<base> (b->id));
+ shared_ptr<derived> d1 (db->load<derived> (d->id));
+ t.commit ();
+
+ {
+ transaction t (db->begin ());
+
+ result r (db->query<root> ("ORDER BY" + query::id));
+ result::iterator i (r.begin ()), e (r.end ());
+
+ assert (i != e && i.load () == r1);
+ assert (++i != e && i.load () == b1);
+ assert (++i != e && i.load () == d1);
+ assert (++i == e);
+
+ t.commit ();
+ }
+ }
+
+ // Erase.
+ //
+ {
+ session s;
+
+ {
+ transaction t (db->begin ());
+ db->load<root> (r->id);
+ db->load<root> (b->id);
+ db->load<root> (d->id);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ db->erase (r);
+ db->erase (b);
+ db->erase (d);
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ assert (!db->find<root> (r->id));
+ assert (!db->find<base> (b->id));
+ assert (!db->find<root> (d->id));
+ t.commit ();
+ }
+ }
+ }
+#endif
+
+ // Test 8: polymorphism and abstract bases.
+ //
+ {
+ using namespace test8;
+
+ base b (1, 1, "b");
+ interm i (2, 2, "i", true);
+ derived1 d1 (3, 3, "d1", true);
+ derived2 d2 (4, 4, "d2", false);
+
+ // Persist.
+ //
+ {
+ transaction t (db->begin ());
+ db->persist (b);
+ db->persist (static_cast<root&> (d1));
+ db->persist (static_cast<interm&> (d2));
+
+ try
+ {
+ db->persist (i);
+ assert (false);
+ }
+ catch (const odb::abstract_class&) {}
+
+ try
+ {
+ db->persist (static_cast<base&> (i));
+ assert (false);
+ }
+ catch (const odb::no_type_info&) {}
+
+ t.commit ();
+ }
+
+ // Load.
+ //
+ {
+ base vb;
+ interm vi;
+ derived1 vd1;
+ derived2 vd2;
+
+ transaction t (db->begin ());
+
+ // load (id)
+ //
+ auto_ptr<root> pb (db->load<root> (b.id));
+ auto_ptr<interm> pd1 (db->load<interm> (d1.id));
+ auto_ptr<derived2> pd2 (db->load<derived2> (d2.id));
+
+ assert (*pb == b);
+ assert (*pd1 == d1);
+ assert (*pd2 == d2);
+
+ // load (id, obj)
+ //
+ db->load (b.id, static_cast<root&> (vb));
+ db->load (d1.id, static_cast<base&> (vd1));
+ db->load (d2.id, static_cast<interm&> (vd2));
+
+ assert (vb == b);
+ assert (vd1 == d1);
+ assert (vd2 == d2);
+
+ try
+ {
+ db->load (i.id, static_cast<root&> (vi));
+ assert (false);
+ }
+ catch (const odb::no_type_info&) {}
+
+ // reload (obj)
+ //
+ vb.num = 0;
+ vd1.num = 0;
+ vd2.num = 0;
+
+ db->reload (static_cast<root&> (vb));
+ db->reload (static_cast<base&> (vd1));
+ db->reload (static_cast<interm&> (vd2));
+
+ assert (vb == b);
+ assert (vd1 == d1);
+ assert (vd2 == d2);
+
+ try
+ {
+ db->reload (static_cast<root&> (vi));
+ assert (false);
+ }
+ catch (const odb::no_type_info&) {}
+
+ t.commit ();
+ }
+
+ // Update.
+ //
+ {
+ b.num++;
+ b.str += 'b';
+ d1.num++;
+ d1.str += "d1";
+ d2.num++;
+ d2.str += "d1";
+
+ {
+ transaction t (db->begin ());
+ db->update (static_cast<root&> (b));
+ db->update (d1);
+ db->update (static_cast<interm&> (d2));
+
+ try
+ {
+ db->update (i);
+ assert (false);
+ }
+ catch (const odb::abstract_class&) {}
+
+ try
+ {
+ db->update (static_cast<base&> (i));
+ assert (false);
+ }
+ catch (const odb::no_type_info&) {}
+
+ t.commit ();
+ }
+
+ {
+ transaction t (db->begin ());
+ auto_ptr<base> pb (db->load<base> (b.id));
+ auto_ptr<root> pd1 (db->load<root> (d1.id));
+ auto_ptr<base> pd2 (db->load<base> (d2.id));
+ t.commit ();
+
+ assert (*pb == b);
+ assert (*pd1 == d1);
+ assert (*pd2 == d2);
+ }
+ }
+
+ // Erase.
+ //
+ {
+ transaction t (db->begin ());
+ db->erase (b);
+ db->erase<interm> (d1.id);
+ db->erase (static_cast<root&> (d2));
+
+ try
+ {
+ db->erase (i);
+ assert (false);
+ }
+ catch (const odb::abstract_class&) {}
+
+ try
+ {
+ db->erase (static_cast<base&> (i));
+ assert (false);
+ }
+ catch (const odb::no_type_info&) {}
+
+ t.commit ();
+ }
+ }
+
+ // Test 9: polymorphism and readonly classes.
+ //
+ {
+ using namespace test9;
+
+ ro_root ro_r (1, 1);
+ rw_base rw_b (2, 2, "b");
+ ro_derived ro_d (3, 3, "d");
+
+ rw_root rw_r (1, 1);
+ ro_base ro_b (2, 2, "b");
+ rw_derived rw_d (3, 3, "d");
+
+ // Persist.
+ //
+ {
+ transaction t (db->begin ());
+ db->persist (ro_r);
+ db->persist (rw_b);
+ db->persist (ro_d);
+
+ db->persist (rw_r);
+ db->persist (ro_b);
+ db->persist (rw_d);
+ t.commit ();
+ }
+
+ // Update.
+ //
+ {
+ ro_root ro_r1 (ro_r);
+ rw_base rw_b1 (rw_b);
+ ro_derived ro_d1 (ro_d);
+
+ ro_base ro_b1 (ro_b);
+ rw_derived rw_d1 (rw_d);
+
+ ro_r1.num++;
+ ro_r1.strs.push_back ("b");
+
+ rw_b1.num++;
+ rw_b1.strs.push_back ("b");
+ rw_b1.str += "b";
+ rw_b1.nums.push_back (2);
+ rw_b.str += "b";
+ rw_b.nums.push_back (2);
+
+ ro_d1.num++;
+ ro_d1.strs.push_back ("d");
+ ro_d1.str += "d";
+ ro_d1.nums.push_back (3);
+ ro_d1.dnum++;
+ ro_d1.dstr += "d";
+
+ rw_r.num++;
+ rw_r.strs.push_back ("b");
+
+ ro_b1.num++;
+ ro_b1.strs.push_back ("b");
+ ro_b1.str += "b";
+ ro_b1.nums.push_back (2);
+
+ rw_d1.num++;
+ rw_d1.strs.push_back ("d");
+ rw_d1.str += "d";
+ rw_d1.nums.push_back (3);
+ rw_d1.dnum++;
+ rw_d1.dstr += "d";
+ rw_d.dnum++;
+ rw_d.dstr += "d";
+
+ {
+ // These should be no-ops.
+ //
+ db->update (ro_r1);
+ db->update (static_cast<ro_root&> (ro_d1));
+ db->update (ro_b1);
+
+ transaction t (db->begin ());
+ db->update (static_cast<ro_root&> (rw_b1));
+ db->update (rw_r);
+ db->update (static_cast<ro_base&> (rw_d1));
+ t.commit ();
+ }
+ }
+
+ // Load.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<ro_root> p_ro_r (db->load<ro_root> (ro_r.id));
+ auto_ptr<ro_root> p_rw_b (db->load<ro_root> (rw_b.id));
+ auto_ptr<ro_root> p_ro_d (db->load<ro_root> (ro_d.id));
+
+ auto_ptr<rw_root> p_rw_r (db->load<rw_root> (rw_r.id));
+ auto_ptr<rw_root> p_ro_b (db->load<rw_root> (ro_b.id));
+ auto_ptr<rw_root> p_rw_d (db->load<rw_root> (rw_d.id));
+ t.commit ();
+
+ assert (*p_ro_r == ro_r);
+ assert (*p_rw_b == rw_b);
+ assert (*p_ro_d == ro_d);
+
+ assert (*p_rw_r == rw_r);
+ assert (*p_ro_b == ro_b);
+ assert (*p_rw_d == rw_d);
+ }
+ }
+
+ // Test 10: empty polymorphic classes.
+ //
+ {
+ using namespace test10;
+
+ base b (1, 1);
+ derived d (2, 2);
+
+ // Persist.
+ //
+ {
+ transaction t (db->begin ());
+ db->persist (b);
+ db->persist (static_cast<root&> (d));
+ t.commit ();
+ }
+
+ // Load.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<root> pb (db->load<root> (b.id));
+ auto_ptr<root> pd (db->load<root> (d.id));
+ t.commit ();
+
+ assert (*pb == b);
+ assert (*pd == d);
+ }
+
+ // Update.
+ //
+ {
+ b.num++;
+ d.num++;
+
+ transaction t (db->begin ());
+ db->update (static_cast<root&> (b));
+ db->update (d);
+ t.commit ();
+ }
+
+ // Load.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<root> pb (db->load<root> (b.id));
+ auto_ptr<root> pd (db->load<root> (d.id));
+ t.commit ();
+
+ assert (*pb == b);
+ assert (*pd == d);
+ }
+ }
+
+ // Test 11: reuse and polymorphic inheritance.
+ //
+ {
+ using namespace test11;
+
+ base b (1, 1, "b");
+ derived d (2, 2, "d");
+
+ b.strs.push_back ("b");
+ b.nums.push_back (1);
+
+ d.strs.push_back ("d");
+ d.nums.push_back (1);
+
+ // Persist.
+ //
+ {
+ transaction t (db->begin ());
+ db->persist (b);
+ db->persist (static_cast<base&> (d));
+ t.commit ();
+ }
+
+ // Load.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<base> pb (db->load<base> (b.id));
+ auto_ptr<base> pd (db->load<base> (d.id));
+ t.commit ();
+
+ assert (*pb == b);
+ assert (*pd == d);
+ }
+
+ // Update.
+ //
+ {
+ b.num++;
+ b.str += "b";
+ b.strs.push_back ("bb");
+ b.nums.push_back (2);
+
+ d.num++;
+ d.str += "d";
+ d.strs.push_back ("dd");
+ d.nums.push_back (2);
+ d.dnum++;
+ d.dstr += "d";
+
+ transaction t (db->begin ());
+ db->update (b);
+ db->update (d);
+ t.commit ();
+ }
+
+ // Load.
+ //
+ {
+ transaction t (db->begin ());
+ auto_ptr<base> pb (db->load<base> (b.id));
+ auto_ptr<base> pd (db->load<base> (d.id));
+ t.commit ();
+
+ assert (*pb == b);
+ assert (*pd == d);
+ }
+
+ // Query.
+ //
+ {
+ typedef odb::query<base> base_query;
+ typedef odb::result<base> base_result;
+
+ typedef odb::query<derived> derived_query;
+ typedef odb::result<derived> derived_result;
+
+ transaction t (db->begin ());
+
+ {
+ base_result qr (db->query<base> (base_query::num == 2));
+ base_result::iterator i (qr.begin ()), e (qr.end ());
+
+ assert (i != e && *i == b);
+ assert (++i == e);
+ }
+
+ {
+ derived_result qr (db->query<derived> (derived_query::num == 3));
+ derived_result::iterator i (qr.begin ()), e (qr.end ());
+
+ assert (i != e && *i == d);
+ assert (++i == e);
+ }
+
+ t.commit ();
+ }
+ }
+ }
+ catch (const odb::exception& e)
+ {
+ cerr << e.what () << endl;
+ return 1;
+ }
+}