From edb5c55e828ad333ce1059b60b6fe97eface5dc4 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 12 Jan 2012 09:02:40 +0200 Subject: Implement callback data re-basing support for LOB result streaming This is used by the query machinery when a copy of the image has to be made. In this case stream_result() needs to use data from the copy of the image, and not from the image that was bound to the bind array. --- odb/oracle/object-result.txx | 15 ++++++++++-- odb/oracle/statement.cxx | 58 +++++++++++++++++++++++++++++++++++--------- odb/oracle/statement.hxx | 18 +++++++++++--- odb/oracle/view-result.txx | 8 +++++- 4 files changed, 82 insertions(+), 17 deletions(-) diff --git a/odb/oracle/object-result.txx b/odb/oracle/object-result.txx index 3cf4e3e..6b68fac 100644 --- a/odb/oracle/object-result.txx +++ b/odb/oracle/object-result.txx @@ -62,7 +62,13 @@ namespace odb use_copy_ ? *image_copy_ : statements_.image ()); object_traits::init (obj, i, db); - statement_->stream_result (); + + // If we are using a copy, make sure the callback information for + // LOB data also comes from the copy. + // + statement_->stream_result ( + use_copy_ ? &statements_.image () : 0, + use_copy_ ? image_copy_ : 0); // Initialize the id image and binding and load the rest of the object // (containers, etc). @@ -208,7 +214,12 @@ namespace odb use_copy_ ? *image_copy_ : statements_.image (), db); - statement_->stream_result (); + // If we are using a copy, make sure the callback information for + // LOB data also comes from the copy. + // + statement_->stream_result ( + use_copy_ ? &statements_.image () : 0, + use_copy_ ? image_copy_ : 0); object_traits::callback (db, obj, callback_event::post_load); } diff --git a/odb/oracle/statement.cxx b/odb/oracle/statement.cxx index bc31d1c..709d07a 100644 --- a/odb/oracle/statement.cxx +++ b/odb/oracle/statement.cxx @@ -971,22 +971,58 @@ namespace odb } void statement:: - stream_result (bind* b, size_t c) + stream_result (bind* b, size_t c, void* obase, void* nbase) { OCIError* err (conn_.error_handle ()); for (size_t i (0); i < c; ++i, ++b) { - // Only stream if the bind specifies a LOB type, and the LOB value is - // not NULL, and a result callback has been provided. + // Only stream if the bind specifies a LOB type. // - if ((b->type == bind::blob || - b->type == bind::clob || - b->type == bind::nclob) && - (b->indicator == 0 || *b->indicator != -1) && - b->callback->callback.result != 0) + if (b->type == bind::blob || + b->type == bind::clob || + b->type == bind::nclob) { - lob* l (static_cast (b->buffer)); + lob* l; + sb2* ind; + lob_callback* cb; + + if (obase == 0) + { + l = static_cast (b->buffer); + ind = b->indicator; + cb = b->callback; + } + else + { + // Re-base the pointers. + // + char* ob (static_cast (obase)); + char* nb (static_cast (nbase)); + + char* p (static_cast (b->buffer)); + assert (ob <= p); + l = reinterpret_cast (nb + (p - ob)); + + if (b->indicator == 0) + ind = 0; + else + { + p = reinterpret_cast (b->indicator); + assert (ob <= p); + ind = reinterpret_cast (nb + (p - ob)); + } + + p = reinterpret_cast (b->callback); + assert (ob <= p); + cb = reinterpret_cast (nb + (p - ob)); + } + + // Nothing to do if the LOB value is NULL or the result callback + // hasn't been provided. + // + if ((ind != 0 && *ind == -1) || cb->callback.result == 0) + continue; ub4 position (0); // Position context. ub1 piece (OCI_FIRST_PIECE); @@ -1040,8 +1076,8 @@ namespace odb // OCI generates and ORA-24343 error when an error code is // returned from a user callback. We simulate this. // - if (!(*b->callback->callback.result) ( - b->callback->context.result, + if (!(*cb->callback.result) ( + cb->context.result, &position, lob_buffer.data (), static_cast (read), diff --git a/odb/oracle/statement.hxx b/odb/oracle/statement.hxx index fa2e879..6aa16e9 100644 --- a/odb/oracle/statement.hxx +++ b/odb/oracle/statement.hxx @@ -84,9 +84,18 @@ namespace odb std::size_t lob_prefetch_size = 0); // Stream the result LOBs, calling user callbacks where necessary. + // The old_base and new_base arguments can be used to "re-base" the + // lob_callback struct pointer (stored in bind::callback), the lob + // struct pointer (stored in bind::buffer), and the indicator value + // pointer (stored in bind::indicator). This is used by the query + // machinery to cause stream_result() to use the callback information + // from a copy of the image instead of the bound image. // void - stream_result (bind*, std::size_t count); + stream_result (bind*, + std::size_t count, + void* old_base = 0, + void* new_base = 0); protected: connection& conn_; @@ -162,9 +171,12 @@ namespace odb fetch (); void - stream_result () + stream_result (void* old_base = 0, void* new_base = 0) { - statement::stream_result (result_.bind, result_.count); + statement::stream_result (result_.bind, + result_.count, + old_base, + new_base); } void diff --git a/odb/oracle/view-result.txx b/odb/oracle/view-result.txx index 9488e2b..ed9b411 100644 --- a/odb/oracle/view-result.txx +++ b/odb/oracle/view-result.txx @@ -52,7 +52,13 @@ namespace odb use_copy_ ? *image_copy_ : statements_.image (), db); - statement_->stream_result (); + // If we are using a copy, make sure the callback information for + // LOB data also comes from the copy. + // + statement_->stream_result ( + use_copy_ ? &statements_.image () : 0, + use_copy_ ? image_copy_ : 0); + view_traits::callback (db, view, callback_event::post_load); } -- cgit v1.1