diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2014-08-14 09:37:06 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2014-11-11 10:27:11 +0200 |
commit | ded152cfb675537ab4ce24f50d0e95cec5b83b18 (patch) | |
tree | c5571f283fa6c0a5735ea4716b0592d9d3b8169d | |
parent | 6375147d5ae76a84dd64f1996cb0d9d501839db6 (diff) |
Draft implementation for INSERT
-rw-r--r-- | odb/database.hxx | 19 | ||||
-rw-r--r-- | odb/database.ixx | 78 | ||||
-rw-r--r-- | odb/database.txx | 139 | ||||
-rw-r--r-- | odb/details/posix/exceptions.cxx | 6 | ||||
-rw-r--r-- | odb/details/posix/exceptions.hxx | 3 | ||||
-rw-r--r-- | odb/details/shared-ptr.hxx | 1 | ||||
-rw-r--r-- | odb/details/shared-ptr/base.cxx | 21 | ||||
-rw-r--r-- | odb/details/shared-ptr/base.hxx | 10 | ||||
-rw-r--r-- | odb/details/shared-ptr/base.ixx | 6 | ||||
-rw-r--r-- | odb/details/shared-ptr/base.txx | 26 | ||||
-rw-r--r-- | odb/details/shared-ptr/exception.hxx | 30 | ||||
-rw-r--r-- | odb/details/win32/exceptions.cxx | 6 | ||||
-rw-r--r-- | odb/details/win32/exceptions.hxx | 3 | ||||
-rw-r--r-- | odb/exception.hxx | 7 | ||||
-rw-r--r-- | odb/exceptions.cxx | 206 | ||||
-rw-r--r-- | odb/exceptions.hxx | 250 | ||||
-rw-r--r-- | odb/forward.hxx | 4 |
17 files changed, 779 insertions, 36 deletions
diff --git a/odb/database.hxx b/odb/database.hxx index 1f56b7f..3ddf914 100644 --- a/odb/database.hxx +++ b/odb/database.hxx @@ -33,6 +33,7 @@ #include <odb/details/mutex.hxx> #include <odb/details/c-string.hxx> #include <odb/details/function-wrapper.hxx> +#include <odb/details/meta/answer.hxx> namespace odb { @@ -77,6 +78,12 @@ namespace odb typename object_traits<T>::id_type persist (const typename object_traits<T>::pointer_type& obj_ptr); + // Bulk persist. + // + template <typename I> + void + persist (I begin, I end); + // Load an object. Throw object_not_persistent if not found. // template <typename T> @@ -489,6 +496,18 @@ namespace odb typename object_traits<T>::id_type persist_ (const typename object_traits<T>::pointer_type&); + template <typename I, database_id DB> + void + persist_ (I, I); + + template <typename I, typename T, database_id DB> + void + persist_ (I, I, details::meta::no ptr); + + template <typename I, typename T, database_id DB> + void + persist_ (I, I, details::meta::yes ptr); + template <typename T, database_id DB> typename object_traits<T>::pointer_type load_ (const typename object_traits<T>::id_type&); diff --git a/odb/database.ixx b/odb/database.ixx index 739db03..d4477e4 100644 --- a/odb/database.ixx +++ b/odb/database.ixx @@ -3,11 +3,62 @@ // license : GNU GPL v2; see accompanying LICENSE file #include <cstring> // std::strlen() +#include <utility> // std::move +#include <iterator> #include <odb/transaction.hxx> namespace odb { + template <typename T> + struct object_pointer_p + { + typedef details::meta::no result_type; + typedef T object_type; + }; + + template <typename T> + struct object_pointer_p<T*> + { + typedef details::meta::yes result_type; + typedef T object_type; + }; + + template <typename T> + struct object_pointer_p<T* const> + { + typedef details::meta::yes result_type; + typedef T object_type; + }; + + template <typename T, template <typename> class P> + struct object_pointer_p<P<T> > + { + typedef details::meta::yes result_type; + typedef T object_type; + }; + + template <typename T, typename A1, template <typename, typename> class P> + struct object_pointer_p<P<T, A1> > + { + typedef details::meta::yes result_type; + typedef T object_type; + }; + + template <typename T, template <typename> class P> + struct object_pointer_p<const P<T> > + { + typedef details::meta::yes result_type; + typedef T object_type; + }; + + template <typename T, typename A1, template <typename, typename> class P> + struct object_pointer_p<const P<T, A1> > + { + typedef details::meta::yes result_type; + typedef T object_type; + }; + inline database:: database (database_id id) : id_ (id), tracer_ (0), schema_version_seq_ (1) @@ -165,6 +216,13 @@ namespace odb return persist_<T, id_common> (pobj); } + template <typename I> + inline void database:: + persist (I b, I e) + { + persist_<I, id_common> (b, e); + } + template <typename T> inline typename object_traits<T>::pointer_type database:: load (const typename object_traits<T>::id_type& id) @@ -622,6 +680,26 @@ namespace odb // Implementations (i.e., the *_() functions). // + template <typename I, database_id DB> + inline void database:: + persist_ (I b, I e) + { + // Sun CC with non-standard STL does not have iterator_traits. + // +#ifndef _RWSTD_NO_CLASS_PARTIAL_SPEC + typedef typename std::iterator_traits<I>::value_type value_type; +#else + // Assume iterator is just a pointer. + // + typedef typename object_pointer_p<I>::object_type value_type; +#endif + + typedef object_pointer_p<value_type> test; + + persist_<I, typename test::object_type, id_common> ( + b, e, typename test::result_type ()); + } + template <typename T, database_id DB> inline typename object_traits<T>::pointer_type database:: find_ (const typename object_traits<T>::id_type& id) diff --git a/odb/database.txx b/odb/database.txx index 5d4829a..8c89394 100644 --- a/odb/database.txx +++ b/odb/database.txx @@ -71,6 +71,145 @@ namespace odb return object_traits::id (obj); } + template <typename I, typename T, database_id DB> + void database:: + persist_ (I b, I e, details::meta::no /*ptr*/) + { + // T can be const T while object_type will always be T. + // + typedef typename object_traits<T>::object_type object_type; + typedef object_traits_impl<object_type, DB> object_traits; + + multiple_exceptions mex; + try + { + while (b != e) + { + std::size_t n (0); + T* a[object_traits::batch]; + + for (; b != e && n < object_traits::batch; ++n) + a[n] = &(*b++); + + object_traits::persist (*this, a, n, &mex); + + if (mex.fatal ()) + break; + + for (std::size_t i (0); i < n; ++i) + { + if (mex[i] != 0) // Don't cache objects that have failed. + continue; + + mex.current (i); // Set position in case the below code throws. + + typename object_traits::reference_cache_traits::position_type p ( + object_traits::reference_cache_traits::insert ( + *this, reference_cache_type<T>::convert (*a[i]))); + + object_traits::reference_cache_traits::persist (p); + } + + mex.delta (n); + } + } + catch (const odb::exception& ex) + { + mex.insert (ex, true); + } + + if (!mex.empty ()) + { + mex.prepare (); + throw mex; + } + } + + namespace details + { + template <typename P> + struct pointer_copy + { + const P* ref; + P copy; + + void assign (const P& p) {ref = &p;} + template <typename P1> void assign (const P1& p1) + { + // The passed pointer should be the same or implicit-convertible + // to the object pointer. This way we make sure the object pointer + // does not assume ownership of the passed object. + // + const P& p (p1); + + copy = p; + ref = © + } + }; + } + + template <typename I, typename T, database_id DB> + void database:: + persist_ (I b, I e, details::meta::yes /*ptr*/) + { + // T can be const T while object_type will always be T. + // + typedef typename object_traits<T>::object_type object_type; + typedef typename object_traits<T>::pointer_type pointer_type; + + typedef object_traits_impl<object_type, DB> object_traits; + + multiple_exceptions mex; + try + { + while (b != e) + { + std::size_t n (0); + T* a[object_traits::batch]; + details::pointer_copy<pointer_type> p[object_traits::batch]; + + for (; b != e && n < object_traits::batch; ++n) + { + p[n].assign (*b++); + a[n] = &pointer_traits<pointer_type>::get_ref (*p[n].ref); + } + + object_traits::persist (*this, a, n, &mex); + + if (mex.fatal ()) + break; + + for (std::size_t i (0); i < n; ++i) + { + if (mex[i] != 0) // Don't cache objects that have failed. + continue; + + mex.current (i); // Set position in case the below code throws. + + // Get the canonical object pointer and insert it into object cache. + // + typename object_traits::pointer_cache_traits::position_type pos ( + object_traits::pointer_cache_traits::insert ( + *this, pointer_cache_type<pointer_type>::convert (*p[i].ref))); + + object_traits::pointer_cache_traits::persist (pos); + } + + mex.delta (n); + } + } + catch (const odb::exception& ex) + { + mex.insert (ex, true); + } + + if (!mex.empty ()) + { + mex.prepare (); + throw mex; + } + } + template <typename T, database_id DB> typename object_traits<T>::pointer_type database:: load_ (const typename object_traits<T>::id_type& id) diff --git a/odb/details/posix/exceptions.cxx b/odb/details/posix/exceptions.cxx index 7a50a13..b8bb702 100644 --- a/odb/details/posix/exceptions.cxx +++ b/odb/details/posix/exceptions.cxx @@ -13,5 +13,11 @@ namespace odb { return "POSIX API error"; } + + posix_exception* posix_exception:: + clone () const + { + return new posix_exception (*this); + } } } diff --git a/odb/details/posix/exceptions.hxx b/odb/details/posix/exceptions.hxx index ebea763..5ff023d 100644 --- a/odb/details/posix/exceptions.hxx +++ b/odb/details/posix/exceptions.hxx @@ -24,6 +24,9 @@ namespace odb virtual const char* what () const throw (); + virtual posix_exception* + clone () const; + private: int code_; }; diff --git a/odb/details/shared-ptr.hxx b/odb/details/shared-ptr.hxx index aecde12..9d2b62f 100644 --- a/odb/details/shared-ptr.hxx +++ b/odb/details/shared-ptr.hxx @@ -9,6 +9,7 @@ #include <odb/details/shared-ptr-fwd.hxx> #include <odb/details/shared-ptr/base.hxx> +#include <odb/details/shared-ptr/exception.hxx> namespace odb { diff --git a/odb/details/shared-ptr/base.cxx b/odb/details/shared-ptr/base.cxx index 590d844..0214c54 100644 --- a/odb/details/shared-ptr/base.cxx +++ b/odb/details/shared-ptr/base.cxx @@ -3,6 +3,7 @@ // license : GNU GPL v2; see accompanying LICENSE file #include <odb/details/shared-ptr/base.hxx> +#include <odb/details/shared-ptr/exception.hxx> using std::size_t; @@ -19,6 +20,12 @@ namespace odb return "object is not shared"; } + not_shared* not_shared:: + clone () const + { + return new not_shared (*this); + } + bool shared_base:: _dec_ref_callback () { @@ -29,6 +36,20 @@ namespace odb return r; } + + namespace bits + { + size_t* locator_common:: + counter (void* x) + { + size_t* p (static_cast<size_t*> (x)); + + if (*(--p) != 0xDEADBEEF) + throw not_shared (); + + return --p; + } + } } } diff --git a/odb/details/shared-ptr/base.hxx b/odb/details/shared-ptr/base.hxx index 6cfe1c9..b16bc8b 100644 --- a/odb/details/shared-ptr/base.hxx +++ b/odb/details/shared-ptr/base.hxx @@ -10,7 +10,6 @@ #include <new> #include <cstddef> // std::size_t -#include <odb/exception.hxx> #include <odb/details/export.hxx> #include <odb/details/shared-ptr/counter-type.hxx> @@ -45,12 +44,6 @@ namespace odb { namespace details { - struct LIBODB_EXPORT not_shared: exception - { - virtual const char* - what () const throw (); - }; - class LIBODB_EXPORT shared_base { public: @@ -69,6 +62,9 @@ namespace odb _ref_count () const; void* + operator new (std::size_t) throw (std::bad_alloc); + + void* operator new (std::size_t, share) throw (std::bad_alloc); void diff --git a/odb/details/shared-ptr/base.ixx b/odb/details/shared-ptr/base.ixx index 53105ce..c5beec6 100644 --- a/odb/details/shared-ptr/base.ixx +++ b/odb/details/shared-ptr/base.ixx @@ -64,6 +64,12 @@ namespace odb } inline void* shared_base:: + operator new (std::size_t n) throw (std::bad_alloc) + { + return ::operator new (n); + } + + inline void* shared_base:: operator new (std::size_t n, share) throw (std::bad_alloc) { return ::operator new (n); diff --git a/odb/details/shared-ptr/base.txx b/odb/details/shared-ptr/base.txx index e00bd5c..7047b7a 100644 --- a/odb/details/shared-ptr/base.txx +++ b/odb/details/shared-ptr/base.txx @@ -13,38 +13,32 @@ namespace odb { // Support for locating the counter in the memory block. // + struct LIBODB_EXPORT locator_common + { + static std::size_t* + counter (void*); + }; + template <typename X, bool poly = meta::polymorphic_p<X>::result> struct locator; template <typename X> - struct locator<X, false> + struct locator<X, false>: locator_common { static std::size_t* counter (X* x) { - std::size_t* p (reinterpret_cast<std::size_t*> (x)); - - if (*(--p) != 0xDEADBEEF) - throw not_shared (); - - return --p; + return locator_common::counter (x); } }; template <typename X> - struct locator<X, true> + struct locator<X, true>: locator_common { static std::size_t* counter (X* x) { - std::size_t* p ( - static_cast<std::size_t*> ( - dynamic_cast<void*> (x))); - - if (*(--p) != 0xDEADBEEF) - throw not_shared (); - - return --p; + return locator_common::counter (dynamic_cast<void*> (x)); } }; diff --git a/odb/details/shared-ptr/exception.hxx b/odb/details/shared-ptr/exception.hxx new file mode 100644 index 0000000..bd7ea38 --- /dev/null +++ b/odb/details/shared-ptr/exception.hxx @@ -0,0 +1,30 @@ +// file : odb/details/shared-ptr/exception.hxx +// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_DETAILS_SHARED_PTR_EXCEPTION_HXX +#define ODB_DETAILS_SHARED_PTR_EXCEPTION_HXX + +#include <odb/pre.hxx> + +#include <odb/exception.hxx> +#include <odb/details/export.hxx> + +namespace odb +{ + namespace details + { + struct LIBODB_EXPORT not_shared: exception + { + virtual const char* + what () const throw (); + + virtual not_shared* + clone () const; + }; + } +} + +#include <odb/post.hxx> + +#endif // ODB_DETAILS_SHARED_PTR_EXCEPTION_HXX diff --git a/odb/details/win32/exceptions.cxx b/odb/details/win32/exceptions.cxx index 75043b4..10605c2 100644 --- a/odb/details/win32/exceptions.cxx +++ b/odb/details/win32/exceptions.cxx @@ -13,5 +13,11 @@ namespace odb { return "Win32 API error"; } + + win32_exception* win32_exception:: + clone () const + { + return new win32_exception (*this); + } } } diff --git a/odb/details/win32/exceptions.hxx b/odb/details/win32/exceptions.hxx index ecc36b6..c987430 100644 --- a/odb/details/win32/exceptions.hxx +++ b/odb/details/win32/exceptions.hxx @@ -26,6 +26,9 @@ namespace odb virtual const char* what () const throw (); + virtual win32_exception* + clone () const; + private: DWORD code_; }; diff --git a/odb/exception.hxx b/odb/exception.hxx index 89b5dae..03a123d 100644 --- a/odb/exception.hxx +++ b/odb/exception.hxx @@ -10,14 +10,19 @@ #include <exception> #include <odb/forward.hxx> // odb::core + #include <odb/details/export.hxx> +#include <odb/details/shared-ptr/base.hxx> namespace odb { - struct LIBODB_EXPORT exception: std::exception + struct LIBODB_EXPORT exception: std::exception, details::shared_base { virtual const char* what () const throw () = 0; + + virtual exception* + clone () const = 0; }; namespace common diff --git a/odb/exceptions.cxx b/odb/exceptions.cxx index a5292bc..6b9a531 100644 --- a/odb/exceptions.cxx +++ b/odb/exceptions.cxx @@ -2,7 +2,9 @@ // copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file +#include <cstring> // std::strlen #include <sstream> + #include <odb/exceptions.hxx> using namespace std; @@ -15,96 +17,192 @@ namespace odb return "NULL pointer"; } + null_pointer* null_pointer:: + clone () const + { + return new null_pointer (*this); + } + const char* already_in_transaction:: what () const throw () { return "transaction already in progress in this thread"; } + already_in_transaction* already_in_transaction:: + clone () const + { + return new already_in_transaction (*this); + } + const char* not_in_transaction:: what () const throw () { return "operation can only be performed in transaction"; } + not_in_transaction* not_in_transaction:: + clone () const + { + return new not_in_transaction (*this); + } + const char* transaction_already_finalized:: what () const throw () { return "transaction already committed or rolled back"; } + transaction_already_finalized* transaction_already_finalized:: + clone () const + { + return new transaction_already_finalized (*this); + } + const char* already_in_session:: what () const throw () { return "session already in effect in this thread"; } + already_in_session* already_in_session:: + clone () const + { + return new already_in_session (*this); + } + const char* not_in_session:: what () const throw () { return "session not in effect in this thread"; } + not_in_session* not_in_session:: + clone () const + { + return new not_in_session (*this); + } + const char* session_required:: what () const throw () { return "session required to load this object relationship"; } + session_required* session_required:: + clone () const + { + return new session_required (*this); + } + const char* deadlock:: what () const throw () { return "transaction aborted due to deadlock"; } + deadlock* deadlock:: + clone () const + { + return new deadlock (*this); + } + const char* connection_lost:: what () const throw () { return "connection to database lost"; } + connection_lost* connection_lost:: + clone () const + { + return new connection_lost (*this); + } + const char* timeout:: what () const throw () { return "database operation timeout"; } + timeout* timeout:: + clone () const + { + return new timeout (*this); + } + const char* object_not_persistent:: what () const throw () { return "object not persistent"; } + object_not_persistent* object_not_persistent:: + clone () const + { + return new object_not_persistent (*this); + } + const char* object_already_persistent:: what () const throw () { return "object already persistent"; } + object_already_persistent* object_already_persistent:: + clone () const + { + return new object_already_persistent (*this); + } + const char* object_changed:: what () const throw () { return "object changed concurrently"; } + object_changed* object_changed:: + clone () const + { + return new object_changed (*this); + } + const char* result_not_cached:: what () const throw () { return "query result is not cached"; } + result_not_cached* result_not_cached:: + clone () const + { + return new result_not_cached (*this); + } + const char* abstract_class:: what () const throw () { return "database operation on instance of abstract class"; } + abstract_class* abstract_class:: + clone () const + { + return new abstract_class (*this); + } + const char* no_type_info:: what () const throw () { return "no type information"; } + no_type_info* no_type_info:: + clone () const + { + return new no_type_info (*this); + } + prepared_already_cached:: prepared_already_cached (const char* name) : name_ (name) @@ -125,6 +223,12 @@ namespace odb return what_.c_str (); } + prepared_already_cached* prepared_already_cached:: + clone () const + { + return new prepared_already_cached (*this); + } + prepared_type_mismatch:: prepared_type_mismatch (const char* name) : name_ (name) @@ -145,6 +249,12 @@ namespace odb return what_.c_str (); } + prepared_type_mismatch* prepared_type_mismatch:: + clone () const + { + return new prepared_type_mismatch (*this); + } + unknown_schema:: unknown_schema (const std::string& name) : name_ (name) @@ -165,6 +275,12 @@ namespace odb return what_.c_str (); } + unknown_schema* unknown_schema:: + clone () const + { + return new unknown_schema (*this); + } + unknown_schema_version:: unknown_schema_version (schema_version v) : version_ (v) @@ -186,15 +302,105 @@ namespace odb return what_.c_str (); } + unknown_schema_version* unknown_schema_version:: + clone () const + { + return new unknown_schema_version (*this); + } + const char* section_not_loaded:: what () const throw () { return "section is not loaded"; } + section_not_loaded* section_not_loaded:: + clone () const + { + return new section_not_loaded (*this); + } + const char* section_not_in_object:: what () const throw () { return "section instance is not part of an object (section was copied?)"; } + + section_not_in_object* section_not_in_object:: + clone () const + { + return new section_not_in_object (*this); + } + + // multiple_exceptions + // + multiple_exceptions:: + ~multiple_exceptions () throw () {} + + void multiple_exceptions:: + insert (size_t p, const odb::exception& e, bool fatal) + { + if (const multiple_exceptions* me = + dynamic_cast<const multiple_exceptions*> (&e)) + { + // Multipe exceptions in the batch. Splice them in. + // + for (iterator i (me->begin ()); i != me->end (); ++i) + set_.insert ( + value_type (delta_ + i->position (), i->exception_ptr ())); + + fatal_ = fatal_ || me->fatal () || fatal; + } + else + { + set_.insert (value_type (delta_ + p, e)); + fatal_ = fatal_ || fatal; + } + } + + const odb::exception* multiple_exceptions:: + lookup (size_t p) const + { + iterator i (set_.find (value_type (p + delta_))); + return i == set_.end () ? 0 : &i->exception (); + } + + void multiple_exceptions:: + prepare () + { + current_ = 0; + delta_ = 0; + + ostringstream os; + os << "multiple exceptions, " + << attempted_ << " element" << (attempted_ != 1 ? "s" : "") << + " attempted, " + << size () << " failed" + << (fatal_ ? ", fatal" : "") << ":"; + + bool nl (true); + for (iterator i (begin ()); i != end (); ++i) + { + const char* w (i->exception ().what ()); + + os << (nl ? "\n" : "") + << '[' << i->position () << "] " << w; + + nl = (w[strlen (w) - 1] != '\n'); + } + + what_ = os.str (); + } + + const char* multiple_exceptions:: + what () const throw () + { + return what_.c_str (); + } + + multiple_exceptions* multiple_exceptions:: + clone () const + { + return new multiple_exceptions (*this); + } } diff --git a/odb/exceptions.hxx b/odb/exceptions.hxx index 14f4f86..98c92d6 100644 --- a/odb/exceptions.hxx +++ b/odb/exceptions.hxx @@ -7,12 +7,15 @@ #include <odb/pre.hxx> +#include <set> #include <string> +#include <cstddef> // std::size_t #include <odb/forward.hxx> // schema_version, odb::core #include <odb/exception.hxx> #include <odb/details/export.hxx> +#include <odb/details/shared-ptr.hxx> namespace odb { @@ -20,6 +23,9 @@ namespace odb { virtual const char* what () const throw (); + + virtual null_pointer* + clone () const; }; // Transaction exceptions. @@ -28,18 +34,27 @@ namespace odb { virtual const char* what () const throw (); + + virtual already_in_transaction* + clone () const; }; struct LIBODB_EXPORT not_in_transaction: odb::exception { virtual const char* what () const throw (); + + virtual not_in_transaction* + clone () const; }; struct LIBODB_EXPORT transaction_already_finalized: odb::exception { virtual const char* what () const throw (); + + virtual transaction_already_finalized* + clone () const; }; // Session exceptions. @@ -48,70 +63,102 @@ namespace odb { virtual const char* what () const throw (); + + virtual already_in_session* + clone () const; }; struct LIBODB_EXPORT not_in_session: odb::exception { virtual const char* what () const throw (); + + virtual not_in_session* + clone () const; }; struct LIBODB_EXPORT session_required: odb::exception { virtual const char* what () const throw (); + + virtual session_required* + clone () const; }; // Database operations exceptions. // struct LIBODB_EXPORT recoverable: odb::exception { + // Abstract. }; struct LIBODB_EXPORT connection_lost: recoverable { virtual const char* what () const throw (); + + virtual connection_lost* + clone () const; }; struct LIBODB_EXPORT timeout: recoverable { virtual const char* what () const throw (); + + virtual timeout* + clone () const; }; struct LIBODB_EXPORT deadlock: recoverable { virtual const char* what () const throw (); + + virtual deadlock* + clone () const; }; struct LIBODB_EXPORT object_not_persistent: odb::exception { virtual const char* what () const throw (); + + virtual object_not_persistent* + clone () const; }; struct LIBODB_EXPORT object_already_persistent: odb::exception { virtual const char* what () const throw (); + + virtual object_already_persistent* + clone () const; }; struct LIBODB_EXPORT object_changed: odb::exception { virtual const char* what () const throw (); + + virtual object_changed* + clone () const; }; struct LIBODB_EXPORT result_not_cached: odb::exception { virtual const char* what () const throw (); + + virtual result_not_cached* + clone () const; }; struct LIBODB_EXPORT database_exception: odb::exception { + // Abstract. }; // Polymorphism support exceptions. @@ -120,12 +167,18 @@ namespace odb { virtual const char* what () const throw (); + + virtual abstract_class* + clone () const; }; struct LIBODB_EXPORT no_type_info: odb::exception { virtual const char* what () const throw (); + + virtual no_type_info* + clone () const; }; // Prepared query support exceptions. @@ -144,6 +197,9 @@ namespace odb virtual const char* what () const throw (); + virtual prepared_already_cached* + clone () const; + private: const char* name_; std::string what_; @@ -155,14 +211,14 @@ namespace odb ~prepared_type_mismatch () throw (); const char* - name () const - { - return name_; - } + name () const {return name_;} virtual const char* what () const throw (); + virtual prepared_type_mismatch* + clone () const; + private: const char* name_; std::string what_; @@ -176,14 +232,14 @@ namespace odb ~unknown_schema () throw (); const std::string& - name () const - { - return name_; - } + name () const {return name_;} virtual const char* what () const throw (); + virtual unknown_schema* + clone () const; + private: std::string name_; std::string what_; @@ -195,14 +251,14 @@ namespace odb ~unknown_schema_version () throw (); schema_version - version () const - { - return version_; - } + version () const {return version_;} virtual const char* what () const throw (); + virtual unknown_schema_version* + clone () const; + private: schema_version version_; std::string what_; @@ -214,12 +270,180 @@ namespace odb { virtual const char* what () const throw (); + + virtual section_not_loaded* + clone () const; }; struct LIBODB_EXPORT section_not_in_object: odb::exception { virtual const char* what () const throw (); + + virtual section_not_in_object* + clone () const; + }; + + // Bulk operation exceptions. + // + struct LIBODB_EXPORT multiple_exceptions: odb::exception + { + struct LIBODB_EXPORT value_type + { + value_type (std::size_t p, const odb::exception& e) + : p_ (p), e_ (e.clone ()) {} + + value_type (std::size_t p, details::shared_ptr<odb::exception> e) + : p_ (p), e_ (e) {} + + std::size_t + position () const {return p_;} + + const odb::exception& + exception () const {return *e_;} + + public: + value_type (std::size_t p): p_ (p) {} // "Key" for set lookup. + + details::shared_ptr<odb::exception> + exception_ptr () const {return e_;} + + private: + std::size_t p_; + details::shared_ptr<odb::exception> e_; + }; + + struct LIBODB_EXPORT comparator_type + { + bool + operator() (const value_type& x, const value_type& y) const + { + return x.position () < y.position (); + } + }; + + typedef std::set<value_type, comparator_type> set_type; + + // Iteration. + // + public: + typedef set_type::const_iterator iterator; + typedef set_type::const_iterator const_iterator; // For pedantic types. + + iterator + begin () const {return set_.begin ();} + + iterator + end () const {return set_.end ();} + + // Lookup. + // + public: + const odb::exception* + operator[] (std::size_t p) const + { + return set_.empty () ? 0 : lookup (p); + } + + // Size and direct set access. + // + public: + std::size_t + size () const {return set_.size ();} + + const set_type& + set () const {return set_;} + + // Severity and attempts. + // + public: + // If fatal() returns true, then (some of) the exceptions were fatal. + // In this case, even for elements that were processed but did not + // cause the exception, no attempts were made to complete the bulk + // operation and the transaction must be aborted. + // + // If fatal() returns false, then the operation on the elements that + // don't have an exception has succeeded. The application can try to + // correct the errors and re-attempt the operation on the elements + // that did cause an exception. In either case, the transactions can + // committed. + // + bool + fatal () const {return fatal_;} + + // Normally you shouldn't need to do this explicitly but you can + // "upgrade" an exception to fatal, for example, for specific + // database error codes. + // + void + fatal (bool f) {fatal_ = fatal_ || f;} + + // Return the number of elements for which the operation has been + // attempted. + // + std::size_t + attempted () const {return attempted_;} + + // odb::exception interface. + // + public: + virtual const char* + what () const throw (); + + virtual multiple_exceptions* + clone () const; + + // Implementation details. + // + public: + ~multiple_exceptions () throw (); + multiple_exceptions (): fatal_ (false), delta_ (0), current_ (0) {} + + // Set the attempted count as (delta + n). + // + void + attempted (std::size_t n) {attempted_ = delta_ + n;} + + // Increment the position of the current batch. Also resets the + // current position in the batch. + // + void + delta (std::size_t d) {delta_ += d; current_ = 0;} + + // Current position in the batch. + // + std::size_t + current () const {return current_;} + + void + current (std::size_t c) {current_ = c;} + + void + insert (std::size_t p, const odb::exception& e, bool fatal = false); + + void + insert (const odb::exception& e, bool fatal = false) + { + insert (current_, e, fatal); + } + + bool + empty () const {return set_.empty ();} + + void + prepare (); + + private: + const odb::exception* + lookup (std::size_t) const; + + private: + set_type set_; + bool fatal_; + std::size_t attempted_; + std::size_t delta_; // Position of the batch. + std::size_t current_; // Position in the batch. + std::string what_; }; namespace common @@ -252,6 +476,8 @@ namespace odb using odb::section_not_loaded; using odb::section_not_in_object; + + using odb::multiple_exceptions; } } diff --git a/odb/forward.hxx b/odb/forward.hxx index 2e54471..29c95f3 100644 --- a/odb/forward.hxx +++ b/odb/forward.hxx @@ -153,6 +153,10 @@ namespace odb class result_impl; class prepared_query_impl; + // + // + struct multiple_exceptions; + // Polymorphism support. // template <typename R> |