From b7a9c4a4efecff45f35652e50d0ae56cea4ade42 Mon Sep 17 00:00:00 2001 From: Constantin Michael Date: Fri, 28 Oct 2011 14:19:20 +0200 Subject: Implement change callbacks for object_result and view_result --- odb/oracle/auto-descriptor.hxx | 2 +- odb/oracle/object-result.hxx | 12 ++++++ odb/oracle/object-result.txx | 78 ++++++++++++++++++++++++++++++++-- odb/oracle/object-statements.txx | 4 +- odb/oracle/oracle-types.hxx | 4 +- odb/oracle/statement.cxx | 91 ++++++++++++++++++++++++++++++++++++++++ odb/oracle/statement.hxx | 13 ++++++ odb/oracle/view-result.hxx | 6 +++ odb/oracle/view-result.txx | 39 ++++++++++++++++- odb/oracle/view-statements.txx | 2 +- 10 files changed, 238 insertions(+), 13 deletions(-) diff --git a/odb/oracle/auto-descriptor.hxx b/odb/oracle/auto-descriptor.hxx index cd537ef..f55925d 100644 --- a/odb/oracle/auto-descriptor.hxx +++ b/odb/oracle/auto-descriptor.hxx @@ -85,7 +85,7 @@ namespace odb d_ = d; } - protected: + private: auto_descriptor (const auto_descriptor&); auto_descriptor& operator= (const auto_descriptor&); diff --git a/odb/oracle/object-result.hxx b/odb/oracle/object-result.hxx index 5e23978..8751948 100644 --- a/odb/oracle/object-result.hxx +++ b/odb/oracle/object-result.hxx @@ -59,8 +59,14 @@ namespace odb using base_type::current; private: + static void + change_callback (void* context); + + private: details::shared_ptr statement_; object_statements& statements_; + bool use_copy_; + typename object_traits::image_type* image_copy_; }; template @@ -97,8 +103,14 @@ namespace odb using base_type::current; private: + static void + change_callback (void* context); + + private: details::shared_ptr statement_; object_statements_no_id& statements_; + bool use_copy_; + typename object_traits::image_type* image_copy_; }; } } diff --git a/odb/oracle/object-result.txx b/odb/oracle/object-result.txx index e3eeca4..66077f3 100644 --- a/odb/oracle/object-result.txx +++ b/odb/oracle/object-result.txx @@ -20,6 +20,8 @@ namespace odb object_result_impl:: ~object_result_impl () { + statements_.image ().change_callback_.callback = 0; + delete image_copy_; } template @@ -29,7 +31,9 @@ namespace odb object_statements& statements) : base_type (statements.connection ().database ()), statement_ (statement), - statements_ (statements) + statements_ (statements), + use_copy_ (false), + image_copy_ (0) { } @@ -45,7 +49,9 @@ namespace odb odb::database& db (this->database ()); object_traits::callback (db, obj, callback_event::pre_load); - typename object_traits::image_type& i (statements_.image ()); + typename object_traits::image_type& i ( + use_copy_ ? *image_copy_ : statements_.image ()); + object_traits::init (obj, i, db); statement_->stream_result (); @@ -85,6 +91,9 @@ namespace odb typename object_traits::image_type& im (statements_.image ()); + im.change_callback_.callback = 0; + use_copy_ = false; + if (im.version != statements_.select_image_version ()) { binding& b (statements_.select_image_binding ()); @@ -95,6 +104,11 @@ namespace odb if (statement_->fetch () == select_statement::no_data) this->end_ = true; + else + { + im.change_callback_.callback = &change_callback; + im.change_callback_.context = this; + } } template @@ -110,6 +124,24 @@ namespace odb throw result_not_cached (); } + template + void object_result_impl:: + change_callback (void* c) + { + object_result_impl* r (static_cast*> (c)); + object_statements& stmts (r->statements_); + + if (r->image_copy_ == 0) + r->image_copy_ = new + typename object_traits::image_type (stmts.image ()); + else + *r->image_copy_ = stmts.image (); + + stmts.select_image_binding ().version++; + stmts.image ().change_callback_.callback = 0; + r->use_copy_ = true; + } + // // object_result_impl_no_id // @@ -118,6 +150,8 @@ namespace odb object_result_impl_no_id:: ~object_result_impl_no_id () { + statements_.image ().change_callback_.callback = 0; + delete image_copy_; } template @@ -127,7 +161,9 @@ namespace odb object_statements_no_id& statements) : base_type (statements.connection ().database ()), statement_ (statement), - statements_ (statements) + statements_ (statements), + use_copy_ (false), + image_copy_ (0) { } @@ -138,8 +174,14 @@ namespace odb odb::database& db (this->database ()); object_traits::callback (db, obj, callback_event::pre_load); - object_traits::init (obj, statements_.image (), db); + + if (use_copy_) + object_traits::init (obj, *image_copy_, db); + else + object_traits::init (obj, statements_.image (), db); + statement_->stream_result (); + object_traits::callback (db, obj, callback_event::post_load); } @@ -151,6 +193,9 @@ namespace odb typename object_traits::image_type& im (statements_.image ()); + im.change_callback_.callback = 0; + use_copy_ = false; + if (im.version != statements_.select_image_version ()) { binding& b (statements_.select_image_binding ()); @@ -161,6 +206,11 @@ namespace odb if (statement_->fetch () == select_statement::no_data) this->end_ = true; + else + { + im.change_callback_.callback = &change_callback; + im.change_callback_.context = this; + } } template @@ -175,5 +225,25 @@ namespace odb { throw result_not_cached (); } + + template + void object_result_impl_no_id:: + change_callback (void* c) + { + object_result_impl_no_id* r ( + static_cast*> (c)); + + object_statements_no_id& stmts (r->statements_); + + if (r->image_copy_ == 0) + r->image_copy_ = new + typename object_traits::image_type (stmts.image ()); + else + *r->image_copy_ = stmts.image (); + + stmts.select_image_binding ().version++; + stmts.image ().change_callback_.callback = 0; + r->use_copy_ = true; + } } } diff --git a/odb/oracle/object-statements.txx b/odb/oracle/object-statements.txx index 948251f..212c03c 100644 --- a/odb/oracle/object-statements.txx +++ b/odb/oracle/object-statements.txx @@ -45,7 +45,7 @@ namespace odb id_image_.version = 0; id_image_version_ = 0; - select_image_binding_.change_callback = &image_.change_callback; + select_image_binding_.change_callback = image_.change_callback (); std::memset (insert_image_bind_, 0, sizeof (insert_image_bind_)); std::memset (update_image_bind_, 0, sizeof (update_image_bind_)); @@ -139,7 +139,7 @@ namespace odb select_image_version_ = 0; insert_image_version_ = 0; - select_image_binding_.change_callback = &image_.change_callback; + select_image_binding_.change_callback = image_.change_callback (); std::memset (insert_image_bind_, 0, sizeof (insert_image_bind_)); std::memset (select_image_bind_, 0, sizeof (select_image_bind_)); diff --git a/odb/oracle/oracle-types.hxx b/odb/oracle/oracle-types.hxx index 1e94894..5587861 100644 --- a/odb/oracle/oracle-types.hxx +++ b/odb/oracle/oracle-types.hxx @@ -141,11 +141,9 @@ namespace odb } lob_auto_descriptor (lob_auto_descriptor& x) - : auto_descriptor (0) + : auto_descriptor (x.d_) { - OCILobLocator* l (x.d_); x.d_ = 0; - reset (l); } lob_auto_descriptor& diff --git a/odb/oracle/statement.cxx b/odb/oracle/statement.cxx index ebddf0c..bddd539 100644 --- a/odb/oracle/statement.cxx +++ b/odb/oracle/statement.cxx @@ -355,6 +355,85 @@ namespace odb } void statement:: + rebind_result (bind* b, size_t c, size_t p) + { + ODB_POTENTIALLY_UNUSED (p); + + OCIError* err (conn_.error_handle ()); + + for (size_t i (1); i <= c; ++i, ++b) + { + if (!(b->type == bind::blob || + b->type == bind::clob || + b->type == bind::nclob)) + continue; + + // When binding a LOB result, the bind::buffer member is + // reinterpreted as a pointer to an auto_descriptor. + // If the descriptor has been reset, it is re-allocated now. + // + auto_descriptor* lob ( + reinterpret_cast*> (b->buffer)); + + if (lob->get () == 0) + { + OCILobLocator* h (0); + + sword r (OCIDescriptorAlloc (conn_.database ().environment (), + reinterpret_cast (&h), + OCI_DTYPE_LOB, + 0, + 0)); + + // OCIDescriptorAlloc will return OCI_SUCCESS on success, or + // OCI_INVALID_HANDLE on an out-of-memory condition. + // + if (r != OCI_SUCCESS) + throw invalid_oci_handle (); + + lob->reset (h); + } + + OCIDefine* h(0); + sword r (OCIDefineByPos (stmt_, + &h, + err, + i, + lob, + sizeof (OCILobLocator*), + result_sqlt_lookup[b->type], + b->indicator, + 0, + 0, + OCI_DEFAULT)); + + if (r == OCI_ERROR || r == OCI_INVALID_HANDLE) + translate_error (err, r); + + // LOB prefetching is only supported in OCI version 11.1 and greater + // and in Oracle server 11.1 and greater. If this code is called + // against a pre 11.1 server, the call to OCIAttrSet will return an + // error code. + // +#if (OCI_MAJOR_VERSION == 11 && OCI_MINOR_VERSION >= 1) \ + || OCI_MAJOR_VERSION > 11 + if (p != 0) + { + r = OCIAttrSet (h, + OCI_HTYPE_DEFINE, + &p, + 0, + OCI_ATTR_LOBPREFETCH_SIZE, + err); + + if (r == OCI_ERROR || r == OCI_INVALID_HANDLE) + translate_error (err, r); + } +#endif + } + } + + void statement:: stream_result (bind* b, size_t c) { OCIError* err (conn_.error_handle()); @@ -456,10 +535,13 @@ namespace odb size_t lob_prefetch_size) : statement (conn, s), data_ (data), + data_version_ (0), + lob_prefetch_size_ (lob_prefetch_size), done_ (true) { bind_param (cond.bind, cond.count, 0); bind_result (data.bind, data.count, lob_prefetch_size); + data_version_ = data_.version; } select_statement:: @@ -469,9 +551,12 @@ namespace odb size_t lob_prefetch_size) : statement (conn, s), data_ (data), + data_version_ (0), + lob_prefetch_size_ (lob_prefetch_size), done_ (true) { bind_result (data.bind, data.count, lob_prefetch_size); + data_version_ = data_.version; } void select_statement:: @@ -526,6 +611,12 @@ namespace odb if (cc != 0 && cc->callback != 0) (cc->callback) (cc->context); + if (data_version_ != data_.version) + { + rebind_result (data_.bind, data_.count, lob_prefetch_size_); + data_version_ = data_.version; + } + sword r (OCIStmtFetch2 (stmt_, conn_.error_handle (), 1, diff --git a/odb/oracle/statement.hxx b/odb/oracle/statement.hxx index d942e82..a883d6c 100644 --- a/odb/oracle/statement.hxx +++ b/odb/oracle/statement.hxx @@ -52,6 +52,17 @@ namespace odb std::size_t count, std::size_t lob_prefetch_size = 0); + // Rebind LOB input parameters. If a query has made a private copy of + // the shared image, any LOB handles that were previously owned by the + // shared image are now owned by the private image of the query. These + // LOB handles need to be reallocated and redefined so that any unfetched + // results may be fetched. + // + void + rebind_result (bind*, + std::size_t count, + std::size_t lob_prefetch_size = 0); + // Stream the result LOBs, calling user callbacks where necessary. // void @@ -106,6 +117,8 @@ namespace odb private: binding& data_; + std::size_t data_version_; + const std::size_t lob_prefetch_size_; bool done_; }; diff --git a/odb/oracle/view-result.hxx b/odb/oracle/view-result.hxx index ec70194..063680f 100644 --- a/odb/oracle/view-result.hxx +++ b/odb/oracle/view-result.hxx @@ -55,8 +55,14 @@ namespace odb using base_type::current; private: + static void + change_callback (void* context); + + private: details::shared_ptr statement_; view_statements& statements_; + bool use_copy_; + typename view_traits::image_type* image_copy_; }; } } diff --git a/odb/oracle/view-result.txx b/odb/oracle/view-result.txx index 8f2262b..361e63e 100644 --- a/odb/oracle/view-result.txx +++ b/odb/oracle/view-result.txx @@ -16,6 +16,8 @@ namespace odb view_result_impl:: ~view_result_impl () { + statements_.image ().change_callback_.callback = 0; + delete image_copy_; } template @@ -25,7 +27,9 @@ namespace odb view_statements& statements) : base_type (statements.connection ().database ()), statement_ (statement), - statements_ (statements) + statements_ (statements), + use_copy_ (false), + image_copy_ (0) { } @@ -36,7 +40,12 @@ namespace odb odb::database& db (this->database ()); view_traits::callback (db, view, callback_event::pre_load); - view_traits::init (view, statements_.image (), db); + + if (use_copy_) + view_traits::init (view, *image_copy_, db); + else + view_traits::init (view, statements_.image (), db); + statement_->stream_result (); view_traits::callback (db, view, callback_event::post_load); } @@ -49,6 +58,9 @@ namespace odb typename view_traits::image_type& im (statements_.image ()); + im.change_callback_.callback = 0; + use_copy_ = false; + if (im.version != statements_.image_version ()) { binding& b (statements_.image_binding ()); @@ -59,6 +71,11 @@ namespace odb if (statement_->fetch () == select_statement::no_data) this->end_ = true; + else + { + im.change_callback_.callback = &change_callback; + im.change_callback_.context = this; + } } template @@ -73,5 +90,23 @@ namespace odb { throw result_not_cached (); } + + template + void view_result_impl:: + change_callback (void* c) + { + view_result_impl* r (static_cast*> (c)); + view_statements& stmts (r->statements_); + + if (r->image_copy_ == 0) + r->image_copy_ = new + typename view_traits::image_type (stmts.image ()); + else + *r->image_copy_ = stmts.image (); + + stmts.image_binding ().version++; + stmts.image ().change_callback_.callback = 0; + r->use_copy_ = true; + } } } diff --git a/odb/oracle/view-statements.txx b/odb/oracle/view-statements.txx index eefe503..9bb601b 100644 --- a/odb/oracle/view-statements.txx +++ b/odb/oracle/view-statements.txx @@ -25,7 +25,7 @@ namespace odb image_.version = 0; image_version_ = 0; - image_binding_.change_callback = &image_.change_callback; + image_binding_.change_callback = image_.change_callback (); std::memset (image_bind_, 0, sizeof (image_bind_)); std::memset (image_indicator_, 0, sizeof (image_indicator_)); -- cgit v1.1