aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--odb/database.hxx8
-rw-r--r--odb/database.ixx43
-rw-r--r--odb/database.txx66
-rw-r--r--odb/exceptions.cxx76
-rw-r--r--odb/exceptions.hxx97
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_;
};