From 8d4d2568f356cb9beb1553bf58ad69c1c800b996 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 14 Aug 2014 09:37:06 +0200 Subject: Implement bulk database operation support for Oracle and SQL Server --- odb/exceptions.hxx | 287 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 275 insertions(+), 12 deletions(-) (limited to 'odb/exceptions.hxx') diff --git a/odb/exceptions.hxx b/odb/exceptions.hxx index 14f4f86..fbf960d 100644 --- a/odb/exceptions.hxx +++ b/odb/exceptions.hxx @@ -7,12 +7,16 @@ #include +#include #include +#include // std::size_t +#include #include // schema_version, odb::core #include #include +#include namespace odb { @@ -20,6 +24,9 @@ namespace odb { virtual const char* what () const throw (); + + virtual null_pointer* + clone () const; }; // Transaction exceptions. @@ -28,18 +35,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 +64,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 +168,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 +198,9 @@ namespace odb virtual const char* what () const throw (); + virtual prepared_already_cached* + clone () const; + private: const char* name_; std::string what_; @@ -155,14 +212,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 +233,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 +252,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 +271,216 @@ 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 + { + 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, + bool maybe, + details::shared_ptr e) + : m_ (maybe), p_ (p), e_ (e) {} + + value_type (std::size_t p): p_ (p) {} // "Key" for set lookup. + + private: + bool m_; + std::size_t p_; + details::shared_ptr 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 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: + // 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); + } + + // Severity, failed and attempt counts. + // + public: + // Return the number of elements for which the operation has been + // attempted. + // + std::size_t + attempted () const {return attempted_;} + + // Return the number of positions for which the operation has failed. + // Note that this count includes the maybe failed positions. + // + 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 + // 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 + // be 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;} + + // odb::exception interface. + // + public: + virtual const char* + what () const throw (); + + virtual multiple_exceptions* + clone () const; + + // Direct set access. + // + public: + const set_type& + set () const {return set_;} + + // Implementation details. + // + public: + ~multiple_exceptions () throw (); + + // 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). + // + 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, + 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) + { + insert (current_, e, fatal); + } + + bool + empty () const {return set_.empty ();} + + void + prepare (); + + private: + const value_type* + lookup (std::size_t p) const; + + private: + const std::type_info& common_exception_ti_; + details::shared_ptr 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::string what_; }; namespace common @@ -252,6 +513,8 @@ namespace odb using odb::section_not_loaded; using odb::section_not_in_object; + + using odb::multiple_exceptions; } } -- cgit v1.1