diff --git a/include/soci/oracle/soci-oracle.h b/include/soci/oracle/soci-oracle.h index de21f0979..4ac7e8449 100644 --- a/include/soci/oracle/soci-oracle.h +++ b/include/soci/oracle/soci-oracle.h @@ -279,7 +279,7 @@ struct oracle_blob_backend : details::blob_backend locator_t get_lob_locator() const; - void set_lob_locator(locator_t locator, bool initialized = true); + void set_lob_locator(const locator_t locator, bool initialized = true); void reset(); diff --git a/src/backends/oracle/blob.cpp b/src/backends/oracle/blob.cpp index 5659af443..ba77d87cb 100644 --- a/src/backends/oracle/blob.cpp +++ b/src/backends/oracle/blob.cpp @@ -146,7 +146,7 @@ oracle_blob_backend::locator_t oracle_blob_backend::get_lob_locator() const return lobp_; } -void oracle_blob_backend::set_lob_locator(oracle_blob_backend::locator_t locator, bool initialized) +void oracle_blob_backend::set_lob_locator(const oracle_blob_backend::locator_t locator, bool initialized) { // If we select a BLOB value into a BLOB object, then the post_fetch code in // the standard_into_type_backend will set this object's locator to the one it is @@ -157,7 +157,11 @@ void oracle_blob_backend::set_lob_locator(oracle_blob_backend::locator_t locator { reset(); - lobp_ = locator; + sword res = OCILobLocatorAssign(session_.svchp_, session_.errhp_, locator, &lobp_); + if (res != OCI_SUCCESS) + { + throw_oracle_soci_error(res, session_.errhp_); + } } initialized_ = initialized; diff --git a/src/backends/oracle/standard-into-type.cpp b/src/backends/oracle/standard-into-type.cpp index 87ba49111..89eb05936 100644 --- a/src/backends/oracle/standard-into-type.cpp +++ b/src/backends/oracle/standard-into-type.cpp @@ -23,6 +23,8 @@ #include #include +#include + #ifdef _MSC_VER #pragma warning(disable:4355) #endif @@ -157,11 +159,24 @@ void oracle_standard_into_type_backend::define_by_pos( oracle_blob_backend *bbe = static_cast(b->get_backend()); - // Reset the blob to ensure that a potentially open temporary BLOB gets - // freed before the locator is changed to point to a different BLOB by the - // to-be-executed statement (which would leave us with a dangling temporary BLOB) + // Reset the blob to ensure that even when the query fails, + // the blob does not contain leftover data from whatever it + // contained before. bbe->reset(); - ociData_ = bbe->get_lob_locator(); + + // Allocate our very own LOB locator. We have to do this instead of + // reusing the locator from the existing Blob object in case the + // statement for which we are binding is going to be executed multiple + // times. If we borrowed the locator from the Blob object, consecutive + // queries would override a previous locator (which might belong + // to an independent Blob object by now). + sword res = OCIDescriptorAlloc(statement_.session_.envhp_, + reinterpret_cast(&ociData_), OCI_DTYPE_LOB, 0, 0); + if (res != OCI_SUCCESS) + { + throw soci_error("Cannot allocate the LOB locator"); + } + size = sizeof(ociData_); data = &ociData_; @@ -384,6 +399,7 @@ void oracle_standard_into_type_backend::clean_up() if (type_ == x_blob) { + OCIDescriptorFree(ociData_, OCI_DTYPE_LOB); ociData_ = NULL; }