From a204ad2d0926919fb19d4f14a2d2c0a5e98acd37 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 6 Sep 2013 08:59:19 +0200 Subject: Additional soft-delete tests --- evolution/soft-delete/driver.cxx | 1132 ++++++++++++++++++++++++++++++++------ evolution/soft-delete/model.hxx | 174 +++++- 2 files changed, 1130 insertions(+), 176 deletions(-) diff --git a/evolution/soft-delete/driver.cxx b/evolution/soft-delete/driver.cxx index b81cca0..7acf6e1 100644 --- a/evolution/soft-delete/driver.cxx +++ b/evolution/soft-delete/driver.cxx @@ -81,10 +81,13 @@ main (int argc, char* argv[]) o.str = "abc"; o.num = 123; o.vec.push_back (123); + o.ptr = new object1 (1); + o.ptr->ptrs.push_back (&o); { transaction t (db->begin ()); db->persist (o); + db->persist (*o.ptr); t.commit (); } } @@ -154,6 +157,98 @@ main (int argc, char* argv[]) } } + // Test basic soft-deleted member logic in polymorphic classes. + // + { + // We have to use v3 here because the discriminator includes + // the namespace. + // + using namespace v3::test9; + + object o (1); + o.bstr = "ab"; + o.dstr = "abc"; + o.num = 123; + + { + transaction t (db->begin ()); + db->persist (o); + t.commit (); + } + } + + // Test soft-deleted section member in polymorphic classes. + // + { + // We have to use v3 here because the discriminator includes + // the namespace. + // + using namespace v3::test10; + + object o (1); + o.bstr = "ab"; + o.dstr = "abc"; + o.num = 123; + + { + transaction t (db->begin ()); + db->persist (o); + t.commit (); + } + } + + // Test soft-deleted members of a section in polymorphic classes. + // + { + // We have to use v3 here because the discriminator includes + // the namespace. + // + using namespace v3::test11; + + object o (1); + o.bstr = "ab"; + o.dstr = "abc"; + o.num = 123; + + { + transaction t (db->begin ()); + db->persist (o); + t.commit (); + } + } + + // Test soft-deleted member and optimistic concurrency. + // + { + using namespace test12; + + object o (1); + o.str = "abc"; + o.num = 123; + + { + transaction t (db->begin ()); + db->persist (o); + t.commit (); + } + } + + // Test soft-deleted member in an object without id. + // + { + using namespace test13; + + object o; + o.str = "abc"; + o.num = 123; + + { + transaction t (db->begin ()); + db->persist (o); + t.commit (); + } + } + #endif // DATABASE_SQLITE // Test soft-deleted container member in a non-versioned object. @@ -229,7 +324,8 @@ main (int argc, char* argv[]) { transaction t (db->begin ()); auto_ptr p (db->load (1)); - assert (p->str == "abc" && p->num == 123 && p->vec[0] == 123); + assert (p->str == "abc" && p->num == 123 && + p->vec[0] == 123 && p->ptr->id_ == 1); t.commit (); } @@ -238,10 +334,12 @@ main (int argc, char* argv[]) typedef odb::result result; transaction t (db->begin ()); - result r (db->query (query::str == "abc")); + result r (db->query (query::str == "abc" && + query::ptr->id == 1)); result::iterator i (r.begin ()); assert (i != r.end () && - i->str == "abc" && i->num == 123 && i->vec[0] == 123); + i->str == "abc" && i->num == 123 && + i->vec[0] == 123 && i->ptr->id_ == 1); t.commit (); } @@ -249,24 +347,32 @@ main (int argc, char* argv[]) o.str = "bcd"; o.num = 234; o.vec.push_back (234); + o.ptr = new object1 (2); + o.ptr->ptrs.push_back (&o); { transaction t (db->begin ()); db->persist (o); + db->persist (*o.ptr); auto_ptr p (db->load (2)); - assert (p->str == "bcd" && p->num == 234 && p->vec[0] == 234); + assert (p->str == "bcd" && p->num == 234 && + p->vec[0] == 234 && p->ptr->id_ == 2); t.commit (); } o.str += 'e'; o.num++; o.vec.modify (0)++; + delete o.ptr; + o.ptr = 0; { transaction t (db->begin ()); + db->erase (2); db->update (o); auto_ptr p (db->load (2)); - assert (p->str == "bcde" && p->num == 235 && p->vec[0] == 235); + assert (p->str == "bcde" && p->num == 235 && + p->vec[0] == 235 && p->ptr == 0); t.commit (); } @@ -467,355 +573,877 @@ main (int argc, char* argv[]) } } -#endif // DATABASE_SQLITE - - // Test soft-deleted container member in a non-versioned object. + // Test basic soft-deleted member logic in polymorphic classes. // { - using namespace test21; + using namespace test9; // All the database operations should still include the deleted // members. // { transaction t (db->begin ()); - auto_ptr p (db->load (1)); - assert (p->num == 123 && p->vec[0] == 123); + auto_ptr p (static_cast (db->load (1))); + assert (p->bstr == "ab" && p->dstr == "abc" && p->num == 123); t.commit (); } { - typedef odb::query query; - typedef odb::result result; + typedef odb::query query; + typedef odb::result result; transaction t (db->begin ()); - result r (db->query (query::num == 123)); + result r (db->query (query::bstr == "ab")); result::iterator i (r.begin ()); - assert (i != r.end () && i->num == 123 && i->vec[0] == 123); + assert (i != r.end ()); + object& o (static_cast (*i)); + assert (o.bstr == "ab" && o.dstr == "abc" && o.num == 123); t.commit (); } object o (2); + o.bstr = "bc"; + o.dstr = "bcd"; o.num = 234; - o.vec.push_back (234); { transaction t (db->begin ()); - db->persist (o); + db->persist (static_cast (o)); auto_ptr p (db->load (2)); - assert (p->num == 234 && p->vec[0] == 234); + assert (p->bstr == "bc" && p->dstr == "bcd" && p->num == 234); t.commit (); } + o.bstr += 'd'; + o.dstr += 'e'; o.num++; - o.vec.modify (0)++; { transaction t (db->begin ()); - db->update (o); + db->update (static_cast (o)); auto_ptr p (db->load (2)); - assert (p->num == 235 && p->vec[0] == 235); + assert (p->bstr == "bcd" && p->dstr == "bcde" && p->num == 235); t.commit (); } { transaction t (db->begin ()); - db->erase (o); + db->erase (static_cast (o)); t.commit (); } } - // Test soft-deleted container member in a non-versioned section. + // Test soft-deleted section member in polymorphic classes. // { - using namespace test22; + using namespace test10; // All the database operations should still include the deleted // members. // { transaction t (db->begin ()); - auto_ptr p (db->load (1)); + auto_ptr p (db->load (1)); db->load (*p, p->s); - assert (p->num == 123 && p->vec[0] == 123); + object& o (static_cast (*p)); + assert (o.bstr == "ab" && o.dstr == "abc" && o.num == 123); t.commit (); } { - typedef odb::query query; - typedef odb::result result; + typedef odb::query query; + typedef odb::result result; transaction t (db->begin ()); - result r (db->query (query::num == 123)); + result r (db->query (query::bstr == "ab")); result::iterator i (r.begin ()); assert (i != r.end ()); db->load (*i, i->s); - assert (i->num == 123 && i->vec[0] == 123); + object& o (static_cast (*i)); + assert (o.bstr == "ab" && o.dstr == "abc" && o.num == 123); t.commit (); } object o (2); + o.bstr = "bc"; + o.dstr = "bcd"; o.num = 234; - o.vec.push_back (234); { transaction t (db->begin ()); - db->persist (o); + db->persist (static_cast (o)); auto_ptr p (db->load (2)); db->load (*p, p->s); - assert (p->num == 234 && p->vec[0] == 234); + assert (p->bstr == "bc" && p->dstr == "bcd" && p->num == 234); t.commit (); } + o.bstr += 'd'; + o.dstr += 'e'; o.num++; - o.vec.modify (0)++; // Automatically marks section as changed. + o.s.change (); { transaction t (db->begin ()); - db->update (o); + db->update (static_cast (o)); auto_ptr p (db->load (2)); db->load (*p, p->s); - assert (p->num == 235 && p->vec[0] == 235); + assert (p->bstr == "bcd" && p->dstr == "bcde" && p->num == 235); t.commit (); } { transaction t (db->begin ()); - db->erase (o); + db->erase (static_cast (o)); t.commit (); } } - if (embedded) - { - transaction t (db->begin ()); - schema_catalog::migrate_schema_post (*db, 3); - t.commit (); - } - break; - } - case 3: - { - using namespace v3; - - // Test soft-deleted objects. - // - { - using namespace test1; - - try - { - transaction t (db->begin ()); - auto_ptr p (db->load (1)); // No such table. - assert (false); - } - catch (const odb::exception&) {} - } - - // SQLite doesn't support dropping of columns. - // -#ifndef DATABASE_SQLITE - - // Test basic soft-deleted member logic. + // Test soft-deleted members of a section in polymorphic classes. // { - using namespace test2; + using namespace test11; - // Now none of the database operations should include the - // deleted members. + // All the database operations should still include the deleted + // members. // { transaction t (db->begin ()); - auto_ptr p (db->load (1)); - assert (p->str == "" && p->num == 123 && p->vec.empty ()); + auto_ptr p (db->load (1)); + db->load (*p, p->s); + object& o (static_cast (*p)); + assert (o.bstr == "ab" && o.dstr == "abc" && o.num == 123); t.commit (); } { - typedef odb::query query; - typedef odb::result result; + typedef odb::query query; + typedef odb::result result; transaction t (db->begin ()); - result r (db->query (query::num == 123)); + result r (db->query (query::bstr == "ab")); result::iterator i (r.begin ()); - assert (i != r.end () && - i->str == "" && i->num == 123 && i->vec.empty ()); - - try - { - db->query (query::str == "abc"); // No such column. - assert (false); - } - catch (const odb::exception&) {} - + assert (i != r.end ()); + db->load (*i, i->s); + object& o (static_cast (*i)); + assert (o.bstr == "ab" && o.dstr == "abc" && o.num == 123); t.commit (); } object o (2); - o.str = "bcd"; + o.bstr = "bc"; + o.dstr = "bcd"; o.num = 234; - o.vec.push_back (234); { transaction t (db->begin ()); - db->persist (o); + db->persist (static_cast (o)); auto_ptr p (db->load (2)); - assert (p->str == "" && p->num == 234 && p->vec.empty ()); + db->load (*p, p->s); + assert (p->bstr == "bc" && p->dstr == "bcd" && p->num == 234); t.commit (); } - o.str += 'e'; + o.bstr += 'd'; + o.dstr += 'e'; o.num++; - o.vec.modify (0)++; + o.s.change (); { transaction t (db->begin ()); - db->update (o); + db->update (static_cast (o)); auto_ptr p (db->load (2)); - assert (p->str == "" && p->num == 235 && p->vec.empty ()); + db->load (*p, p->s); + assert (p->bstr == "bcd" && p->dstr == "bcde" && p->num == 235); t.commit (); } { transaction t (db->begin ()); - db->erase (2); + db->erase (static_cast (o)); t.commit (); } } - // Test empty statement handling (INSERT, UPDATE). + // Test soft-deleted member and optimistic concurrency. // { - using namespace test3; + using namespace test12; - // Now none of the database operations should include the - // deleted member. + // All the database operations should still include the deleted + // members. // - object o; + { + transaction t (db->begin ()); + auto_ptr p (db->load (1)); + assert (p->str == "abc" && p->num == 123); + t.commit (); + } + + { + typedef odb::query query; + typedef odb::result result; + + transaction t (db->begin ()); + result r (db->query (query::str == "abc")); + result::iterator i (r.begin ()); + assert (i != r.end () && i->str == "abc" && i->num == 123); + t.commit (); + } + + object o (2); o.str = "bcd"; + o.num = 234; { transaction t (db->begin ()); db->persist (o); - auto_ptr p (db->load (o.id)); - assert (p->str == ""); + auto_ptr p (db->load (2)); + assert (p->str == "bcd" && p->num == 234); t.commit (); } o.str += 'e'; + o.num++; { transaction t (db->begin ()); + unsigned long long v (o.v_); db->update (o); - auto_ptr p (db->load (o.id)); - assert (p->str == ""); + assert (o.v_ != v); + auto_ptr p (db->load (2)); + assert (p->str == "bcde" && p->num == 235 && p->v_ == o.v_); t.commit (); } - } - - // Test empty statement handling (SELECT in polymorphic loader). - // - { - using namespace test4; - - // Now none of the database operations should include the - // deleted member. - // - object o (1); - o.str = "abc"; { transaction t (db->begin ()); - db->persist (o); - auto_ptr p (db->load (1)); - assert (static_cast (*p).str == ""); + db->erase (o); t.commit (); } } - // Test container with soft-deleted value member. + // Test soft-deleted member in an object without id. // { - using namespace test5; + using namespace test13; - // Now none of the database operations should include the - // deleted members. + typedef odb::query query; + typedef odb::result result; + + // All the database operations should still include the deleted + // members. // { transaction t (db->begin ()); - auto_ptr p (db->load (1)); - assert (p->vec[0].str == "" && p->vec[0].num == 123); + result r (db->query (query::str == "abc")); + result::iterator i (r.begin ()); + assert (i != r.end () && i->str == "abc" && i->num == 123); t.commit (); } - object o (2); - o.vec.push_back (value ("bcd", 234)); + object o; + o.str = "bcd"; + o.num = 234; { transaction t (db->begin ()); db->persist (o); - auto_ptr p (db->load (2)); - assert (p->vec[0].str == "" && p->vec[0].num == 234); - t.commit (); - } - o.vec.modify (0).str += 'e'; - o.vec.modify (0).num++; + result r (db->query (query::str == "bcd")); + result::iterator i (r.begin ()); + assert (i != r.end () && i->str == "bcd" && i->num == 234); - { - transaction t (db->begin ()); - db->update (o); - auto_ptr p (db->load (2)); - assert (p->vec[0].str == "" && p->vec[0].num == 235); t.commit (); } { transaction t (db->begin ()); - db->erase (2); + db->erase_query (query::str == "bcd"); t.commit (); } } - // Test view with soft-deleted member. - // +#endif // DATABASE_SQLITE + + // Test soft-deleted container member in a non-versioned object. + // + { + using namespace test21; + + // All the database operations should still include the deleted + // members. + // + { + transaction t (db->begin ()); + auto_ptr p (db->load (1)); + assert (p->num == 123 && p->vec[0] == 123); + t.commit (); + } + + { + typedef odb::query query; + typedef odb::result result; + + transaction t (db->begin ()); + result r (db->query (query::num == 123)); + result::iterator i (r.begin ()); + assert (i != r.end () && i->num == 123 && i->vec[0] == 123); + t.commit (); + } + + object o (2); + o.num = 234; + o.vec.push_back (234); + + { + transaction t (db->begin ()); + db->persist (o); + auto_ptr p (db->load (2)); + assert (p->num == 234 && p->vec[0] == 234); + t.commit (); + } + + o.num++; + o.vec.modify (0)++; + + { + transaction t (db->begin ()); + db->update (o); + auto_ptr p (db->load (2)); + assert (p->num == 235 && p->vec[0] == 235); + t.commit (); + } + + { + transaction t (db->begin ()); + db->erase (o); + t.commit (); + } + } + + // Test soft-deleted container member in a non-versioned section. + // + { + using namespace test22; + + // All the database operations should still include the deleted + // members. + // + { + transaction t (db->begin ()); + auto_ptr p (db->load (1)); + db->load (*p, p->s); + assert (p->num == 123 && p->vec[0] == 123); + t.commit (); + } + + { + typedef odb::query query; + typedef odb::result result; + + transaction t (db->begin ()); + result r (db->query (query::num == 123)); + result::iterator i (r.begin ()); + assert (i != r.end ()); + db->load (*i, i->s); + assert (i->num == 123 && i->vec[0] == 123); + t.commit (); + } + + object o (2); + o.num = 234; + o.vec.push_back (234); + + { + transaction t (db->begin ()); + db->persist (o); + auto_ptr p (db->load (2)); + db->load (*p, p->s); + assert (p->num == 234 && p->vec[0] == 234); + t.commit (); + } + + o.num++; + o.vec.modify (0)++; // Automatically marks section as changed. + + { + transaction t (db->begin ()); + db->update (o); + auto_ptr p (db->load (2)); + db->load (*p, p->s); + assert (p->num == 235 && p->vec[0] == 235); + t.commit (); + } + + { + transaction t (db->begin ()); + db->erase (o); + t.commit (); + } + } + + if (embedded) + { + transaction t (db->begin ()); + schema_catalog::migrate_schema_post (*db, 3); + t.commit (); + } + break; + } + case 3: + { + using namespace v3; + + // Test soft-deleted objects. + // + { + using namespace test1; + + try + { + transaction t (db->begin ()); + auto_ptr p (db->load (1)); // No such table. + assert (false); + } + catch (const odb::exception&) {} + } + + // SQLite doesn't support dropping of columns. + // +#ifndef DATABASE_SQLITE + + // Test basic soft-deleted member logic. + // + { + using namespace test2; + + // Now none of the database operations should include the + // deleted members. + // + { + transaction t (db->begin ()); + auto_ptr p (db->load (1)); + assert (p->str == "" && p->num == 123 && + p->vec.empty () && p->ptr == 0); + t.commit (); + } + + { + typedef odb::query query; + typedef odb::result result; + + transaction t (db->begin ()); + result r (db->query (query::num == 123)); + result::iterator i (r.begin ()); + assert (i != r.end () && + i->str == "" && i->num == 123 && + i->vec.empty () && i->ptr == 0); + + try + { + db->query (query::str == "abc"); // No such column. + assert (false); + } + catch (const odb::exception&) {} + + t.commit (); + } + + object o (2); + o.str = "bcd"; + o.num = 234; + o.vec.push_back (234); + o.ptr = new object1 (2); + o.ptr->ptrs.push_back (&o); + + { + transaction t (db->begin ()); + db->persist (o); + db->persist (*o.ptr); + auto_ptr p (db->load (2)); + assert (p->str == "" && p->num == 234 && + p->vec.empty () && p->ptr == 0); + t.commit (); + } + + o.str += 'e'; + o.num++; + o.vec.modify (0)++; + delete o.ptr; + o.ptr = 0; + + { + transaction t (db->begin ()); + db->erase (2); + db->update (o); + auto_ptr p (db->load (2)); + assert (p->str == "" && p->num == 235 && + p->vec.empty () && p->ptr == 0); + t.commit (); + } + + { + transaction t (db->begin ()); + db->erase (2); + t.commit (); + } + } + + // Test empty statement handling (INSERT, UPDATE). + // + { + using namespace test3; + + // Now none of the database operations should include the + // deleted member. + // + object o; + o.str = "bcd"; + + { + transaction t (db->begin ()); + db->persist (o); + auto_ptr p (db->load (o.id)); + assert (p->str == ""); + t.commit (); + } + + o.str += 'e'; + + { + transaction t (db->begin ()); + db->update (o); + auto_ptr p (db->load (o.id)); + assert (p->str == ""); + t.commit (); + } + } + + // Test empty statement handling (SELECT in polymorphic loader). + // + { + using namespace test4; + + // Now none of the database operations should include the + // deleted member. + // + object o (1); + o.str = "abc"; + + { + transaction t (db->begin ()); + db->persist (o); + auto_ptr p (db->load (1)); + assert (static_cast (*p).str == ""); + t.commit (); + } + } + + // Test container with soft-deleted value member. + // + { + using namespace test5; + + // Now none of the database operations should include the + // deleted members. + // + { + transaction t (db->begin ()); + auto_ptr p (db->load (1)); + assert (p->vec[0].str == "" && p->vec[0].num == 123); + t.commit (); + } + + object o (2); + o.vec.push_back (value ("bcd", 234)); + + { + transaction t (db->begin ()); + db->persist (o); + auto_ptr p (db->load (2)); + assert (p->vec[0].str == "" && p->vec[0].num == 234); + t.commit (); + } + + o.vec.modify (0).str += 'e'; + o.vec.modify (0).num++; + + { + transaction t (db->begin ()); + db->update (o); + auto_ptr p (db->load (2)); + assert (p->vec[0].str == "" && p->vec[0].num == 235); + t.commit (); + } + + { + transaction t (db->begin ()); + db->erase (2); + t.commit (); + } + } + + // Test view with soft-deleted member. + // + { + using namespace test6; + + // Now none of the database operations should include the + // deleted members. + // + { + typedef odb::query query; + typedef odb::result result; + + transaction t (db->begin ()); + result r (db->query (query::num == 123)); + result::iterator i (r.begin ()); + assert (i != r.end () && i->str == "" && i->num == 123); + + try + { + db->query (query::str == "abc"); // No such column. + assert (false); + } + catch (const odb::exception&) {} + + t.commit (); + } + } + + // Test soft-deleted section member. + // + { + using namespace test7; + + // Now none of the database operations should include the + // deleted members. + // + { + transaction t (db->begin ()); + auto_ptr p (db->load (1)); + + try + { + db->load (*p, p->s); // No such column. + assert (false); + } + catch (const odb::exception&) {} + + t.commit (); + } + + object o (2); + o.str = "bcd"; + o.num = 234; + o.vec.push_back (234); + + { + transaction t (db->begin ()); + db->persist (o); + t.commit (); + } + + o.str += 'e'; + o.num++; + o.vec.modify (0)++; + o.s.change (); + + { + transaction t (db->begin ()); + db->update (o); + t.commit (); + } + + { + transaction t (db->begin ()); + db->erase (2); + t.commit (); + } + } + + // Test soft-deleted members of a section. + // + { + using namespace test8; + + // Now none of the database operations should include the + // deleted members. + // + { + transaction t (db->begin ()); + auto_ptr p (db->load (1)); + db->load (*p, p->s); + assert (p->str == "" && p->num == 123 && p->vec.empty ()); + t.commit (); + } + + { + typedef odb::query query; + typedef odb::result result; + + transaction t (db->begin ()); + result r (db->query (query::num == 123)); + result::iterator i (r.begin ()); + assert (i != r.end ()); + db->load (*i, i->s); + assert (i->str == "" && i->num == 123 && i->vec.empty ()); + + try + { + db->query (query::str == "abc"); // No such column. + assert (false); + } + catch (const odb::exception&) {} + + t.commit (); + } + + object o (2); + o.str = "bcd"; + o.num = 234; + o.vec.push_back (234); + + { + transaction t (db->begin ()); + db->persist (o); + auto_ptr p (db->load (2)); + db->load (*p, p->s); + assert (p->str == "" && p->num == 234 && p->vec.empty ()); + t.commit (); + } + + o.str += 'e'; + o.num++; + o.vec.modify (0)++; // No longer automatically marked as changed. + + { + transaction t (db->begin ()); + db->update (o); + auto_ptr p (db->load (2)); + db->load (*p, p->s); + assert (p->str == "" && p->num == 234 && p->vec.empty ()); + t.commit (); + } + + o.s.change (); + + { + transaction t (db->begin ()); + db->update (o); + auto_ptr p (db->load (2)); + db->load (*p, p->s); + assert (p->str == "" && p->num == 235 && p->vec.empty ()); + t.commit (); + } + + { + transaction t (db->begin ()); + db->erase (2); + t.commit (); + } + } + + // Test basic soft-deleted member logic in polymorphic classes. + // { - using namespace test6; + using namespace test9; // Now none of the database operations should include the // deleted members. // { - typedef odb::query query; - typedef odb::result result; + transaction t (db->begin ()); + auto_ptr p (static_cast (db->load (1))); + assert (p->bstr == "" && p->dstr == "" && p->num == 123); + t.commit (); + } + + { + typedef odb::query query; + typedef odb::result result; transaction t (db->begin ()); - result r (db->query (query::num == 123)); + result r (db->query (query::id == 1)); result::iterator i (r.begin ()); - assert (i != r.end () && i->str == "" && i->num == 123); + assert (i != r.end ()); + object& o (static_cast (*i)); + assert (o.bstr == "" && o.dstr == "" && o.num == 123); try { - db->query (query::str == "abc"); // No such column. + db->query (query::bstr == "ab"); // No such column. + assert (false); + } + catch (const odb::exception&) {} + + t.commit (); + } + + { + typedef odb::query query; + typedef odb::result result; + + transaction t (db->begin ()); + result r (db->query (query::num == 123)); + result::iterator i (r.begin ()); + assert (i != r.end () && + i->bstr == "" && i->dstr == "" && i->num); + + try + { + db->query (query::dstr == "abc"); // No such column. assert (false); } catch (const odb::exception&) {} t.commit (); } + + object o (2); + o.bstr = "bc"; + o.dstr = "bcd"; + o.num = 234; + + { + transaction t (db->begin ()); + db->persist (static_cast (o)); + auto_ptr p (db->load (2)); + assert (p->bstr == "" && p->dstr == "" && p->num == 234); + t.commit (); + } + + o.bstr += 'd'; + o.dstr += 'e'; + o.num++; + + { + transaction t (db->begin ()); + db->update (static_cast (o)); + auto_ptr p (db->load (2)); + assert (p->bstr == "" && p->dstr == "" && p->num == 235); + t.commit (); + } + + { + transaction t (db->begin ()); + db->erase (2); + t.commit (); + } } - // Test soft-deleted section member. + // Test soft-deleted section member in polymorphic classes. // { - using namespace test7; + using namespace test10; // Now none of the database operations should include the // deleted members. // { transaction t (db->begin ()); - auto_ptr p (db->load (1)); + auto_ptr p (db->load (1)); try { @@ -828,47 +1456,70 @@ main (int argc, char* argv[]) } object o (2); - o.str = "bcd"; + o.bstr = "bc"; + o.dstr = "bcd"; o.num = 234; - o.vec.push_back (234); { transaction t (db->begin ()); - db->persist (o); + db->persist (static_cast (o)); t.commit (); } - o.str += 'e'; + o.bstr += 'd'; + o.dstr += 'e'; o.num++; - o.vec.modify (0)++; o.s.change (); { transaction t (db->begin ()); - db->update (o); + db->update (static_cast (o)); t.commit (); } { transaction t (db->begin ()); - db->erase (2); + db->erase (2); t.commit (); } } - // Test soft-deleted members of a section. + // Test soft-deleted members of a section in polymorphic classes. // { - using namespace test8; + using namespace test11; // Now none of the database operations should include the // deleted members. // { transaction t (db->begin ()); - auto_ptr p (db->load (1)); + auto_ptr p (db->load (1)); db->load (*p, p->s); - assert (p->str == "" && p->num == 123 && p->vec.empty ()); + object& o (static_cast (*p)); + assert (o.bstr == "" && o.dstr == "" && o.num == 123); + t.commit (); + } + + { + typedef odb::query query; + typedef odb::result result; + + transaction t (db->begin ()); + result r (db->query (query::id == 1)); + result::iterator i (r.begin ()); + db->load (*i, i->s); + assert (i != r.end ()); + object& o (static_cast (*i)); + assert (o.bstr == "" && o.dstr == "" && o.num == 123); + + try + { + db->query (query::bstr == "ab"); // No such column. + assert (false); + } + catch (const odb::exception&) {} + t.commit (); } @@ -879,13 +1530,13 @@ main (int argc, char* argv[]) transaction t (db->begin ()); result r (db->query (query::num == 123)); result::iterator i (r.begin ()); - assert (i != r.end ()); db->load (*i, i->s); - assert (i->str == "" && i->num == 123 && i->vec.empty ()); + assert (i != r.end () && + i->bstr == "" && i->dstr == "" && i->num); try { - db->query (query::str == "abc"); // No such column. + db->query (query::dstr == "abc"); // No such column. assert (false); } catch (const odb::exception&) {} @@ -894,40 +1545,122 @@ main (int argc, char* argv[]) } object o (2); - o.str = "bcd"; + o.bstr = "bc"; + o.dstr = "bcd"; o.num = 234; - o.vec.push_back (234); { transaction t (db->begin ()); - db->persist (o); + db->persist (static_cast (o)); auto_ptr p (db->load (2)); db->load (*p, p->s); - assert (p->str == "" && p->num == 234 && p->vec.empty ()); + assert (p->bstr == "" && p->dstr == "" && p->num == 234); t.commit (); } - o.str += 'e'; + o.bstr += 'd'; + o.dstr += 'e'; o.num++; - o.vec.modify (0)++; // No longer automatically marked as changed. + o.s.change (); { transaction t (db->begin ()); - db->update (o); + db->update (static_cast (o)); auto_ptr p (db->load (2)); db->load (*p, p->s); - assert (p->str == "" && p->num == 234 && p->vec.empty ()); + assert (p->bstr == "" && p->dstr == "" && p->num == 235); t.commit (); } - o.s.change (); + { + transaction t (db->begin ()); + db->erase (2); + t.commit (); + } + + // Test empty statement detection in sections. + // + base b (3); + b.bstr = "bc"; + + { + transaction t (db->begin ()); + db->persist (b); + auto_ptr p (db->load (3)); + db->load (*p, p->s); + assert (p->bstr == ""); + t.commit (); + } + + b.bstr += 'd'; + b.s.change (); + + { + transaction t (db->begin ()); + db->update (b); + auto_ptr p (db->load (3)); + db->load (*p, p->s); + assert (p->bstr == ""); + t.commit (); + } + } + + // Test soft-deleted member and optimistic concurrency. + // + { + using namespace test12; + + // Now none of the database operations should include the + // deleted members. + // + { + transaction t (db->begin ()); + auto_ptr p (db->load (1)); + assert (p->str == "" && p->num == 123); + t.commit (); + } + + { + typedef odb::query query; + typedef odb::result result; + + transaction t (db->begin ()); + result r (db->query (query::num == 123)); + result::iterator i (r.begin ()); + assert (i != r.end () && i->str == "" && i->num == 123); + + try + { + db->query (query::str == "abc"); // No such column. + assert (false); + } + catch (const odb::exception&) {} + + t.commit (); + } + + object o (2); + o.str = "bcd"; + o.num = 234; + + { + transaction t (db->begin ()); + db->persist (o); + auto_ptr p (db->load (2)); + assert (p->str == "" && p->num == 234); + t.commit (); + } + + o.str += 'e'; + o.num++; { transaction t (db->begin ()); + unsigned long long v (o.v_); db->update (o); + assert (o.v_ != v); auto_ptr p (db->load (2)); - db->load (*p, p->s); - assert (p->str == "" && p->num == 235 && p->vec.empty ()); + assert (p->str == "" && p->num == 235 && p->v_ == o.v_); t.commit (); } @@ -938,6 +1671,55 @@ main (int argc, char* argv[]) } } + // Test soft-deleted member in an object without id. + // + { + using namespace test13; + + typedef odb::query query; + typedef odb::result result; + + // Now none of the database operations should include the + // deleted members. + // + { + transaction t (db->begin ()); + result r (db->query (query::num == 123)); + result::iterator i (r.begin ()); + assert (i != r.end () && i->str == "" && i->num == 123); + + try + { + db->query (query::str == "abc"); // No such column. + assert (false); + } + catch (const odb::exception&) {} + + t.commit (); + } + + object o; + o.str = "bcd"; + o.num = 234; + + { + transaction t (db->begin ()); + db->persist (o); + + result r (db->query (query::num == 234)); + result::iterator i (r.begin ()); + assert (i != r.end () && i->str == "" && i->num == 234); + + t.commit (); + } + + { + transaction t (db->begin ()); + db->erase_query (query::num == 234); + t.commit (); + } + } + #endif // DATABASE_SQLITE // Test soft-deleted container member in a non-versioned object. diff --git a/evolution/soft-delete/model.hxx b/evolution/soft-delete/model.hxx index 5defcac..5df2cee 100644 --- a/evolution/soft-delete/model.hxx +++ b/evolution/soft-delete/model.hxx @@ -11,6 +11,7 @@ #include #include #include +#include #include // DATABASE_XXX @@ -51,10 +52,24 @@ namespace MODEL_NAMESPACE(MODEL_VERSION) #pragma db namespace table("t2_") namespace test2 { + struct object; + + #pragma db object + struct object1 + { + object1 (unsigned long id = 0): id_ (id) {} + + #pragma db id + unsigned long id_; + + odb::vector > ptrs; + }; + #pragma db object struct object { - object (unsigned long id = 0): id_ (id) {} + object (unsigned long id = 0): id_ (id), ptr (0) {} + ~object () {delete ptr;} #pragma db id unsigned long id_; @@ -62,11 +77,15 @@ namespace MODEL_NAMESPACE(MODEL_VERSION) std::string str; unsigned long num; odb::vector vec; + + #pragma db inverse(ptrs) + object1* ptr; }; #if MODEL_VERSION == 3 #pragma db member(object::str) deleted(3) #pragma db member(object::vec) deleted(3) + #pragma db member(object::ptr) deleted(3) #endif } @@ -241,6 +260,159 @@ namespace MODEL_NAMESPACE(MODEL_VERSION) #endif } + // Test basic soft-deleted member logic in polymorphic classes. + // + #pragma db namespace table("t9_") + namespace test9 + { + #pragma db object polymorphic + struct base + { + virtual + ~base () {} + base (unsigned long id = 0): id_ (id) {} + + #pragma db id + unsigned long id_; + + std::string bstr; + }; + + #pragma db object + struct object: base + { + object (unsigned long id = 0): base (id) {} + + std::string dstr; + unsigned long num; + }; + +#if MODEL_VERSION == 3 + #pragma db member(base::bstr) deleted(3) + #pragma db member(object::dstr) deleted(3) +#endif + } + + // Test soft-deleted section member in polymorphic classes. + // + #pragma db namespace table("t10_") + namespace test10 + { + #pragma db object polymorphic + struct base + { + virtual + ~base () {} + base (unsigned long id = 0): id_ (id) {} + + #pragma db id + unsigned long id_; + + #pragma db load(lazy) update(change) + odb::section s; + + #pragma db section(s) + std::string bstr; + }; + + #pragma db object + struct object: base + { + object (unsigned long id = 0): base (id) {} + + #pragma db section(s) + std::string dstr; + + unsigned long num; + }; + +#if MODEL_VERSION == 3 + #pragma db member(base::s) deleted(3) +#endif + } + + // Test soft-deleted members of a section in polymorphic classes. + // + #pragma db namespace table("t11_") + namespace test11 + { + #pragma db object polymorphic + struct base + { + virtual + ~base () {} + base (unsigned long id = 0): id_ (id) {} + + #pragma db id + unsigned long id_; + + #pragma db load(lazy) update(change) + odb::section s; + + #pragma db section(s) + std::string bstr; + }; + + #pragma db object + struct object: base + { + object (unsigned long id = 0): base (id) {} + + #pragma db section(s) + std::string dstr; + + #pragma db section(s) + unsigned long num; + }; + +#if MODEL_VERSION == 3 + #pragma db member(base::bstr) deleted(3) + #pragma db member(object::dstr) deleted(3) +#endif + } + + // Test soft-deleted member and optimistic concurrency. + // + #pragma db namespace table("t12_") + namespace test12 + { + #pragma db object optimistic + struct object + { + object (unsigned long id = 0): id_ (id) {} + + #pragma db id + unsigned long id_; + + #pragma db version mssql:type("ROWVERSION") + unsigned long long v_; + + std::string str; + unsigned long num; + }; + +#if MODEL_VERSION == 3 + #pragma db member(object::str) deleted(3) +#endif + } + + // Test soft-deleted member in an object without id. + // + #pragma db namespace table("t13_") + namespace test13 + { + #pragma db object no_id + struct object + { + std::string str; + unsigned long num; + }; + +#if MODEL_VERSION == 3 + #pragma db member(object::str) deleted(3) +#endif + } + #endif // DATABASE_SQLITE // Test soft-deleted container member in a non-versioned object. -- cgit v1.1