diff options
-rw-r--r-- | odb/database.hxx | 8 | ||||
-rw-r--r-- | odb/database.ixx | 43 | ||||
-rw-r--r-- | odb/database.txx | 66 | ||||
-rw-r--r-- | odb/exceptions.cxx | 76 | ||||
-rw-r--r-- | odb/exceptions.hxx | 97 |
5 files changed, 218 insertions, 72 deletions
diff --git a/odb/database.hxx b/odb/database.hxx index d399209..f4a3d36 100644 --- a/odb/database.hxx +++ b/odb/database.hxx @@ -566,6 +566,14 @@ namespace odb void erase_ (const typename object_traits<T>::pointer_type&); + template <typename I, typename T, database_id DB> + void + erase_id_ (I, I); + + template <typename I, database_id DB> + void + erase_object_ (I, I); + template <typename T, database_id DB, typename Q> typename object_traits<T>::pointer_type query_one_ (const Q&); diff --git a/odb/database.ixx b/odb/database.ixx index 9a9b892..a17e90a 100644 --- a/odb/database.ixx +++ b/odb/database.ixx @@ -7,56 +7,68 @@ #include <iterator> #include <odb/transaction.hxx> +#include <odb/pointer-traits.hxx> namespace odb { template <typename T> - struct object_pointer_p + struct object_pointer_traits { typedef details::meta::no result_type; typedef T object_type; + static const T& get_ref (const T& x) {return x;} }; template <typename T> - struct object_pointer_p<T*> + struct object_pointer_traits<T*> { typedef details::meta::yes result_type; typedef T object_type; + static const T& get_ref (const T* p) {return *p;} }; template <typename T> - struct object_pointer_p<T* const> + struct object_pointer_traits<T* const> { typedef details::meta::yes result_type; typedef T object_type; + static const T& get_ref (const T* p) {return *p;} }; template <typename T, template <typename> class P> - struct object_pointer_p<P<T> > + struct object_pointer_traits<P<T> > { typedef details::meta::yes result_type; typedef T object_type; + static const T& get_ref (const P<T>& p) { + return pointer_traits<P<T> >::get_ref (p);} }; template <typename T, typename A1, template <typename, typename> class P> - struct object_pointer_p<P<T, A1> > + struct object_pointer_traits<P<T, A1> > { typedef details::meta::yes result_type; typedef T object_type; + static const T& get_ref (const P<T, A1>& p) { + return pointer_traits<P<T, A1> >::get_ref (p);} }; template <typename T, template <typename> class P> - struct object_pointer_p<const P<T> > + struct object_pointer_traits<const P<T> > { typedef details::meta::yes result_type; typedef T object_type; + static const T& get_ref (const P<T>& p) { + return pointer_traits<P<T> >::get_ref (p);} }; template <typename T, typename A1, template <typename, typename> class P> - struct object_pointer_p<const P<T, A1> > + struct object_pointer_traits<const P<T, A1> > { typedef details::meta::yes result_type; typedef T object_type; + static const T& get_ref (const P<T, A1>& p) { + return pointer_traits<P<T, A1> >::get_ref (p);} }; inline database:: @@ -477,7 +489,14 @@ namespace odb inline void database:: erase (I idb, I ide) { - erase_<T, I, id_common> (idb, ide); + erase_id_<I, T, id_common> (idb, ide); + } + + template <typename I> + inline void database:: + erase (I ob, I oe) + { + erase_object_<I, id_common> (ob, oe); } template <typename T> @@ -698,13 +717,13 @@ namespace odb #else // Assume iterator is just a pointer. // - typedef typename object_pointer_p<I>::object_type value_type; + typedef typename object_pointer_traits<I>::object_type value_type; #endif - typedef object_pointer_p<value_type> test; + typedef object_pointer_traits<value_type> opt; - persist_<I, typename test::object_type, id_common> ( - b, e, typename test::result_type ()); + persist_<I, typename opt::object_type, id_common> ( + b, e, typename opt::result_type ()); } template <typename T, database_id DB> diff --git a/odb/database.txx b/odb/database.txx index 8003345..943f31c 100644 --- a/odb/database.txx +++ b/odb/database.txx @@ -86,7 +86,7 @@ namespace odb while (b != e) { std::size_t n (0); - T* a[object_traits::batch]; + object_type* a[object_traits::batch]; for (; b != e && n < object_traits::batch; ++n) a[n] = &(*b++); @@ -159,13 +159,13 @@ namespace odb typedef object_traits_impl<object_type, DB> object_traits; - multiple_exceptions mex; + multiple_exceptions mex (typeid (object_already_persistent)); try { while (b != e) { std::size_t n (0); - T* a[object_traits::batch]; + object_type* a[object_traits::batch]; details::pointer_copy<pointer_type> p[object_traits::batch]; for (; b != e && n < object_traits::batch; ++n) @@ -279,9 +279,9 @@ namespace odb throw section_not_in_object (); } - template <typename T, typename I, database_id DB> + template <typename I, typename T, database_id DB> void database:: - erase_ (I b, I e) + erase_id_ (I b, I e) { // T is explicitly specified by the caller, so assume it is object type. // @@ -289,7 +289,7 @@ namespace odb typedef object_traits_impl<object_type, DB> object_traits; typedef typename object_traits::id_type id_type; - multiple_exceptions mex; + multiple_exceptions mex (typeid (object_not_persistent)); try { while (b != e) @@ -323,6 +323,60 @@ namespace odb } } + template <typename I, database_id DB> + void database:: + erase_object_ (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_traits<I>::object_type value_type; +#endif + + // object_pointer_traits<T>::object_type can be const. + // + typedef object_pointer_traits<value_type> opt; + + typedef + typename object_traits<typename opt::object_type>::object_type + object_type; + + typedef object_traits_impl<object_type, DB> object_traits; + + multiple_exceptions mex (typeid (object_not_persistent)); + try + { + while (b != e) + { + std::size_t n (0); + const object_type* a[object_traits::batch]; + + for (; b != e && n < object_traits::batch; ++n) + a[n] = &opt::get_ref (*b++); + + object_traits::erase (*this, a, n, &mex); + + if (mex.fatal ()) + break; + + 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> struct database::query_<T, DB, class_object> diff --git a/odb/exceptions.cxx b/odb/exceptions.cxx index 6b9a531..ca9e84c 100644 --- a/odb/exceptions.cxx +++ b/odb/exceptions.cxx @@ -4,6 +4,7 @@ #include <cstring> // std::strlen #include <sstream> +#include <cassert> #include <odb/exceptions.hxx> @@ -256,7 +257,7 @@ namespace odb } unknown_schema:: - unknown_schema (const std::string& name) + unknown_schema (const string& name) : name_ (name) { what_ = "unknown database schema '"; @@ -338,31 +339,31 @@ namespace odb ~multiple_exceptions () throw () {} void multiple_exceptions:: - insert (size_t p, const odb::exception& e, bool fatal) + insert (size_t p, bool maybe, 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 ())); + details::shared_ptr<odb::exception> pe; - fatal_ = fatal_ || me->fatal () || fatal; - } + if (common_exception_ti_ != typeid (e)) + pe.reset (e.clone ()); else { - set_.insert (value_type (delta_ + p, e)); - fatal_ = fatal_ || fatal; + if (common_exception_ == 0) + common_exception_.reset (e.clone ()); + + pe = common_exception_; } + + set_.insert (value_type (delta_ + p, maybe, pe)); + fatal_ = fatal_ || fatal; } - const odb::exception* multiple_exceptions:: + const multiple_exceptions::value_type* multiple_exceptions:: lookup (size_t p) const { - iterator i (set_.find (value_type (p + delta_))); - return i == set_.end () ? 0 : &i->exception (); + p += delta_; // Called while populating multiple_exceptions. + + iterator i (set_.find (value_type (p))); + return i == set_.end () ? 0 : &*i; } void multiple_exceptions:: @@ -370,22 +371,49 @@ namespace odb { current_ = 0; delta_ = 0; + common_exception_.reset (); ostringstream os; os << "multiple exceptions, " << attempted_ << " element" << (attempted_ != 1 ? "s" : "") << " attempted, " - << size () << " failed" + << failed () << " failed" << (fatal_ ? ", fatal" : "") << ":"; bool nl (true); - for (iterator i (begin ()); i != end (); ++i) + for (iterator i (begin ()); i != end ();) { - const char* w (i->exception ().what ()); - - os << (nl ? "\n" : "") - << '[' << i->position () << "] " << w; - + size_t p (i->position ()); + const odb::exception& e (i->exception ()); + + os << (nl ? "\n" : ""); + + if (!i->maybe ()) + { + os << '[' << p << ']'; + ++i; + } + else + { + // In this case we will normally have a large number of maybe + // failures in a row (usually the whole batch). So let's try + // to represent them all as a single range. + // + size_t n (0); + for (++i; i != end () && i->maybe (); ++i) + { + assert (&e == &i->exception ()); // The same common exception. + n++; + } + + if (n == 0) + os << '[' << p << ']'; + else + os << '[' << p << '-' << (p + n) << "] (some)"; + } + + const char* w (e.what ()); + os << ' ' << w; nl = (w[strlen (w) - 1] != '\n'); } diff --git a/odb/exceptions.hxx b/odb/exceptions.hxx index e8ee227..fbf960d 100644 --- a/odb/exceptions.hxx +++ b/odb/exceptions.hxx @@ -9,7 +9,8 @@ #include <set> #include <string> -#include <cstddef> // std::size_t +#include <cstddef> // std::size_t +#include <typeinfo> #include <odb/forward.hxx> // schema_version, odb::core #include <odb/exception.hxx> @@ -290,25 +291,33 @@ namespace odb { 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_;} + // If true, then this means that some positions in the batch have + // triggered the exception but it is not possible, due to the + // limitations of the underlying database API, to discern exactly + // which ones. As a result, all the positions in the batch are + // marked as "maybe failed". + // + bool + maybe () const {return m_;} + const odb::exception& exception () const {return *e_;} + // Implementation details. + // public: - value_type (std::size_t p): p_ (p) {} // "Key" for set lookup. + value_type (std::size_t p, + bool maybe, + details::shared_ptr<odb::exception> e) + : m_ (maybe), p_ (p), e_ (e) {} - details::shared_ptr<odb::exception> - exception_ptr () const {return e_;} + value_type (std::size_t p): p_ (p) {} // "Key" for set lookup. private: + bool m_; std::size_t p_; details::shared_ptr<odb::exception> e_; }; @@ -339,24 +348,32 @@ namespace odb // Lookup. // public: - const odb::exception* + // Return NULL if the element at this position has no exception. Note + // that the returned value is value_type* and not odb::exception* in + // order to provide access to maybe(); see value_type::maybe() for + // details. + // + const value_type* operator[] (std::size_t p) const { return set_.empty () ? 0 : lookup (p); } - // Size and direct set access. + // Severity, failed and attempt counts. // public: + // Return the number of elements for which the operation has been + // attempted. + // std::size_t - size () const {return set_.size ();} - - const set_type& - set () const {return set_;} + attempted () const {return attempted_;} - // Severity and attempts. + // Return the number of positions for which the operation has failed. + // Note that this count includes the maybe failed positions. // - public: + std::size_t + failed () const {return set_.size ();} + // 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 @@ -378,12 +395,6 @@ namespace odb 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: @@ -393,11 +404,25 @@ namespace odb virtual multiple_exceptions* clone () const; + // Direct set access. + // + public: + const set_type& + set () const {return set_;} + // Implementation details. // public: ~multiple_exceptions () throw (); - multiple_exceptions (): fatal_ (false), delta_ (0), current_ (0) {} + + // All instances of the common exception must be equal since we are + // going to create and share just one. + // + multiple_exceptions (const std::type_info& common_exception_ti) + : common_exception_ti_ (common_exception_ti), + fatal_ (false), + delta_ (0), + current_ (0) {} // Set the attempted count as (delta + n). // @@ -419,7 +444,16 @@ namespace odb current (std::size_t c) {current_ = c;} void - insert (std::size_t p, const odb::exception& e, bool fatal = false); + insert (std::size_t p, + bool maybe, + const odb::exception& e, + bool fatal = false); + + void + insert (std::size_t p, const odb::exception& e, bool fatal = false) + { + insert (p, false, e, fatal); + } void insert (const odb::exception& e, bool fatal = false) @@ -434,15 +468,18 @@ namespace odb prepare (); private: - const odb::exception* - lookup (std::size_t) const; + const value_type* + lookup (std::size_t p) const; private: + const std::type_info& common_exception_ti_; + details::shared_ptr<odb::exception> common_exception_; + 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::size_t delta_; // Position of the batch. + std::size_t current_; // Position in the batch. std::string what_; }; |