aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2014-08-14 09:37:06 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2014-11-11 10:27:11 +0200
commitded152cfb675537ab4ce24f50d0e95cec5b83b18 (patch)
treec5571f283fa6c0a5735ea4716b0592d9d3b8169d
parent6375147d5ae76a84dd64f1996cb0d9d501839db6 (diff)
Draft implementation for INSERT
-rw-r--r--odb/database.hxx19
-rw-r--r--odb/database.ixx78
-rw-r--r--odb/database.txx139
-rw-r--r--odb/details/posix/exceptions.cxx6
-rw-r--r--odb/details/posix/exceptions.hxx3
-rw-r--r--odb/details/shared-ptr.hxx1
-rw-r--r--odb/details/shared-ptr/base.cxx21
-rw-r--r--odb/details/shared-ptr/base.hxx10
-rw-r--r--odb/details/shared-ptr/base.ixx6
-rw-r--r--odb/details/shared-ptr/base.txx26
-rw-r--r--odb/details/shared-ptr/exception.hxx30
-rw-r--r--odb/details/win32/exceptions.cxx6
-rw-r--r--odb/details/win32/exceptions.hxx3
-rw-r--r--odb/exception.hxx7
-rw-r--r--odb/exceptions.cxx206
-rw-r--r--odb/exceptions.hxx250
-rw-r--r--odb/forward.hxx4
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 = &copy;
+ }
+ };
+ }
+
+ 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>