// file : common/transaction/callback/driver.cxx // copyright : Copyright (c) 2009-2015 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file // Test transaction callbacks. // #include <cstddef> // std::size_t #include <cassert> #include <iostream> #include <odb/database.hxx> #include <odb/transaction.hxx> #include <common/common.hxx> using namespace std; using namespace odb::core; struct callback { callback (unsigned short v): v_ (v), t_ (0) {} callback (unsigned short v, transaction& t): v_ (v), t_ (0) {register_ (t);} ~callback () {if (t_ != 0) unregister ();} void register_ (transaction& t) { t_ = &t; t.callback_register (&func, this, transaction::event_all, v_, &t_); } void unregister () { cout << " unregister callback " << v_ << endl; t_->callback_unregister (this); t_ = 0; } void update (unsigned short v) { v_ = v; t_->callback_update (this, transaction::event_all, v_, &t_); } private: static void func (unsigned short event, void* key, unsigned long long data) { callback& c (*static_cast<callback*> (key)); const char* en; switch (event) { case transaction::event_commit: en = "commit"; break; case transaction::event_rollback: en = "rollback"; break; default: en = "unknown"; } cout << " callback " << c.v_ << " " << en << endl; assert (data == c.v_); assert (c.t_ == 0); } unsigned short v_; transaction* t_; }; struct failed {}; static void throw_func (unsigned short, void*, unsigned long long) { throw failed (); } static void dummy_func (unsigned short, void* key, unsigned long long data) { assert (reinterpret_cast<unsigned long long> (key) == data); } static void fill (transaction& t) { // 20 is from odb/transaction.hxx. // for (size_t i (0); i < 20; ++i) t.callback_register (&dummy_func, reinterpret_cast<void*> (i), transaction::event_all, i); } int main (int argc, char* argv[]) { try { auto_ptr<database> db (create_database (argc, argv, false)); // We want to test both stack and dynamic slots. // for (unsigned short i (1); i < 3; ++i) { // Test basic logic. // cout << "test " << i << "/001" << endl; // Commit callback. // { transaction t (db->begin ()); if (i == 2) fill (t); callback c1 (1, t); t.commit (); } // Rollback callback. // { transaction t (db->begin ()); if (i == 2) fill (t); callback c1 (1, t); t.rollback (); } // Rollback via exception callback. // { callback c1 (1); try { transaction t (db->begin ()); if (i == 2) fill (t); c1.register_ (t); throw failed (); } catch (const failed&) { } } // Unregister callback at the end. // { transaction t (db->begin ()); if (i == 2) fill (t); callback c1 (1, t); c1.unregister (); t.callback_unregister (&c1); // Test unregistering non-registered key. t.commit (); } { transaction t (db->begin ()); if (i == 2) fill (t); callback c1 (1, t); c1.unregister (); callback c2 (2, t); t.commit (); } // Unregister callback in the middle. // cout << "test " << i << "/002" << endl; { transaction t (db->begin ()); if (i == 2) fill (t); callback c1 (1, t); callback c2 (2, t); callback c3 (3, t); c2.unregister (); t.commit (); } { transaction t (db->begin ()); if (i == 2) fill (t); callback c1 (1, t); callback c2 (2, t); callback c3 (3, t); c2.unregister (); callback c4 (4, t); // Using the free slot. t.commit (); } // Test a callback in the middle that throws. // cout << "test " << i << "/003" << endl; try { transaction t (db->begin ()); if (i == 2) fill (t); callback c1 (1, t); t.callback_register (&throw_func, 0); callback c2 (2, t); t.commit (); } catch (const failed&) { } // Test callback_update(). // { transaction t (db->begin ()); if (i == 2) fill (t); callback c (1, t); c.update (2); t.commit (); } } } catch (const odb::exception& e) { cerr << e.what () << endl; return 1; } }