From 0fb66e3e85ccb096cb625bf4664fdbbf3b8a29f9 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 10 Nov 2011 16:23:24 +0200 Subject: Add descriptor management flags for TIMESTAMP and INTERVAL image types For a query expression that has only by-value parameters, we guarantee that it can be used by multiple threads. However, the way we handle TIMESTAMP and INTERVAL types now requires the modification of the image during query execution. To resolve this, the datetime, interval_ym, and interval_ds image types now have flags that allow the query implementation to avoid the modification. --- odb/oracle/oracle-types.cxx | 197 ++++++++++++++------ odb/oracle/oracle-types.hxx | 146 +++++---------- odb/oracle/query.hxx | 124 ++++++++++-- odb/oracle/statement.cxx | 445 ++++++++++++++++++++++++++++++++------------ odb/oracle/statement.hxx | 9 + 5 files changed, 636 insertions(+), 285 deletions(-) diff --git a/odb/oracle/oracle-types.cxx b/odb/oracle/oracle-types.cxx index fad085f..9de57cd 100644 --- a/odb/oracle/oracle-types.cxx +++ b/odb/oracle/oracle-types.cxx @@ -14,10 +14,64 @@ namespace odb { namespace oracle { + // + // datetime + // + + datetime:: + ~datetime () + { + if (descriptor != 0 && (flags & descriptor_free)) + OCIDescriptorFree (descriptor, OCI_DTYPE_TIMESTAMP); + } + + datetime:: + datetime (datetime& x) + : environment (x.environment), + error (x.error), + descriptor (x.descriptor), + flags (x.flags), + year_ (x.year_), + month_ (x.month_), + day_ (x.day_), + hour_ (x.hour_), + minute_ (x.minute_), + second_ (x.second_), + nanosecond_ (x.nanosecond_) + { + x.descriptor = 0; + } + + datetime& datetime:: + operator= (datetime& x) + { + if (this != &x) + { + if (descriptor != 0 && (flags & descriptor_free)) + OCIDescriptorFree (descriptor, OCI_DTYPE_TIMESTAMP); + + environment = x.environment; + error = x.error; + descriptor = x.descriptor; + flags = x.flags; + year_ = x.year_; + month_ = x.month_; + day_ = x.day_; + hour_ = x.hour_; + minute_ = x.minute_; + second_ = x.second_; + nanosecond_ = x.nanosecond_; + + x.descriptor = 0; + } + + return *this; + } + void datetime:: get (sb2& y, ub1& m, ub1& d, ub1& h, ub1& minute, ub1& s, ub4& ns) const { - assert (descriptor.get () != 0); + assert (descriptor != 0); sword r (OCIDateTimeGetDate (environment, error, @@ -44,7 +98,7 @@ namespace odb void datetime:: set (sb2 y, ub1 m, ub1 d, ub1 h, ub1 minute, ub1 s, ub4 ns) { - if (descriptor.get () != 0) + if (descriptor != 0) { sword r (OCIDateTimeConstruct (environment, error, @@ -74,32 +128,54 @@ namespace odb } } - void datetime:: - set () + // + // interval_ym + // + + interval_ym:: + ~interval_ym () { - assert (descriptor.get () != 0); - - sword r (OCIDateTimeConstruct (environment, - error, - descriptor, - year_, - month_, - day_, - hour_, - minute_, - second_, - nanosecond_, - 0, - 0)); + if (descriptor != 0 && (flags & descriptor_free)) + OCIDescriptorFree (descriptor, OCI_DTYPE_INTERVAL_YM); + } - if (r != OCI_SUCCESS) - translate_error (error, r); + interval_ym:: + interval_ym (interval_ym& x) + : environment (x.environment), + error (x.error), + descriptor (x.descriptor), + flags (x.flags), + year_ (x.year_), + month_ (x.month_) + { + x.descriptor = 0; + } + + interval_ym& interval_ym:: + operator= (interval_ym& x) + { + if (this != &x) + { + if (descriptor != 0 && (flags & descriptor_free)) + OCIDescriptorFree (descriptor, OCI_DTYPE_INTERVAL_YM); + + environment = x.environment; + error = x.error; + descriptor = x.descriptor; + flags = x.flags; + year_ = x.year_; + month_ = x.month_; + + x.descriptor = 0; + } + + return *this; } void interval_ym:: get (sb4& y, sb4& m) const { - assert (descriptor.get () != 0); + assert (descriptor != 0); sword r (OCIIntervalGetYearMonth (environment, error, @@ -114,7 +190,7 @@ namespace odb void interval_ym:: set (sb4 y, sb4 m) { - if (descriptor.get () != 0) + if (descriptor != 0) { sword r (OCIIntervalSetYearMonth (environment, error, @@ -132,25 +208,60 @@ namespace odb } } - void interval_ym:: - set () + // + // interval_ds + // + + interval_ds:: + ~interval_ds () { - assert (descriptor.get () != 0); + if (descriptor != 0 && (flags & descriptor_free)) + OCIDescriptorFree (descriptor, OCI_DTYPE_INTERVAL_DS); + } - sword r (OCIIntervalSetYearMonth (environment, - error, - year_, - month_, - descriptor)); + interval_ds:: + interval_ds (interval_ds& x) + : environment (x.environment), + error (x.error), + descriptor (x.descriptor), + flags (x.flags), + day_ (x.day_), + hour_ (x.hour_), + minute_ (x.minute_), + second_ (x.second_), + nanosecond_ (x.nanosecond_) + { + x.descriptor = 0; + } - if (r != OCI_SUCCESS) - translate_error (error, r); + interval_ds& interval_ds:: + operator= (interval_ds& x) + { + if (this != &x) + { + if (descriptor != 0 && (flags & descriptor_free)) + OCIDescriptorFree (descriptor, OCI_DTYPE_INTERVAL_DS); + + environment = x.environment; + error = x.error; + descriptor = x.descriptor; + flags = x.flags; + day_ = x.day_; + hour_ = x.hour_; + minute_ = x.minute_; + second_ = x.second_; + nanosecond_ = x.nanosecond_; + + x.descriptor = 0; + } + + return *this; } void interval_ds:: get (sb4& d, sb4& h, sb4& m, sb4& s, sb4& ns) const { - assert (descriptor.get () != 0); + assert (descriptor != 0); sword r (OCIIntervalGetDaySecond (environment, error, @@ -168,7 +279,7 @@ namespace odb void interval_ds:: set (sb4 d, sb4 h, sb4 m, sb4 s, sb4 ns) { - if (descriptor.get () != 0) + if (descriptor != 0) { sword r (OCIIntervalSetDaySecond (environment, error, @@ -191,23 +302,5 @@ namespace odb nanosecond_ = ns; } } - - void interval_ds:: - set () - { - assert (descriptor.get () != 0); - - sword r (OCIIntervalSetDaySecond (environment, - error, - day_, - hour_, - minute_, - second_, - nanosecond_, - descriptor)); - - if (r != OCI_SUCCESS) - translate_error (error, r); - } } } diff --git a/odb/oracle/oracle-types.hxx b/odb/oracle/oracle-types.hxx index a4500d3..5e08a87 100644 --- a/odb/oracle/oracle-types.hxx +++ b/odb/oracle/oracle-types.hxx @@ -169,90 +169,6 @@ namespace odb } }; - class LIBODB_ORACLE_EXPORT datetime_auto_descriptor: - public auto_descriptor - { - typedef auto_descriptor base; - - public: - datetime_auto_descriptor (OCIDateTime* d = 0): - base (d) - { - } - - datetime_auto_descriptor (datetime_auto_descriptor& x): - base (x.d_) - { - x.d_ = 0; - } - - datetime_auto_descriptor& - operator= (datetime_auto_descriptor& x) - { - OCIDateTime* l (x.d_); - x.d_ = 0; - reset (l); - - return *this; - } - }; - - class LIBODB_ORACLE_EXPORT interval_ym_auto_descriptor: - public auto_descriptor - { - typedef auto_descriptor base; - - public: - interval_ym_auto_descriptor (OCIInterval* d = 0): - base (d) - { - } - - interval_ym_auto_descriptor (interval_ym_auto_descriptor& x): - base (x.d_) - { - x.d_ = 0; - } - - interval_ym_auto_descriptor& - operator= (interval_ym_auto_descriptor& x) - { - OCIInterval* l (x.d_); - x.d_ = 0; - reset (l); - - return *this; - } - }; - - class LIBODB_ORACLE_EXPORT interval_ds_auto_descriptor: - public auto_descriptor - { - typedef auto_descriptor base; - - public: - interval_ds_auto_descriptor (OCIInterval* d = 0): - base (d) - { - } - - interval_ds_auto_descriptor (interval_ds_auto_descriptor& x): - base (x.d_) - { - x.d_ = 0; - } - - interval_ds_auto_descriptor& - operator= (interval_ds_auto_descriptor& x) - { - OCIInterval* l (x.d_); - x.d_ = 0; - reset (l); - - return *this; - } - }; - // // The OCIDateTime and OCIInterval APIs require that an environment and // error handle be passed to any function that manipulates an OCIDateTime @@ -265,6 +181,11 @@ namespace odb // consistency. // + // Descriptor management flags. + // + const unsigned short descriptor_cache = 0x01; + const unsigned short descriptor_free = 0x02; + struct LIBODB_ORACLE_EXPORT datetime { void @@ -285,16 +206,25 @@ namespace odb ub1 second, ub4 nanosecond); - void - set (); - public: OCIEnv* environment; OCIError* error; + OCIDateTime* descriptor; + + unsigned short flags; + + public: + datetime (unsigned short f = descriptor_cache | descriptor_free) + : descriptor (0), flags (f) + { + } - datetime_auto_descriptor descriptor; + datetime (datetime&); + datetime& operator= (datetime&); - private: + ~datetime (); + + public: sb2 year_; ub1 month_; ub1 day_; @@ -312,16 +242,25 @@ namespace odb void set (sb4 year, sb4 month); - void - set (); - public: OCIEnv* environment; OCIError* error; + OCIInterval* descriptor; + + unsigned short flags; + + public: + interval_ym (unsigned short f = descriptor_cache | descriptor_free) + : descriptor (0), flags (f) + { + } + + interval_ym (interval_ym&); + interval_ym& operator= (interval_ym&); - interval_ym_auto_descriptor descriptor; + ~interval_ym (); - private: + public: sb4 year_; sb4 month_; }; @@ -342,16 +281,25 @@ namespace odb sb4 second, sb4 nanosecond); - void - set (); - public: OCIEnv* environment; OCIError* error; + OCIInterval* descriptor; + + unsigned short flags; + + public: + interval_ds (unsigned short f = descriptor_cache | descriptor_free) + : descriptor (0), flags (f) + { + } - interval_ds_auto_descriptor descriptor; + interval_ds (interval_ds&); + interval_ds& operator= (interval_ds&); - private: + ~interval_ds (); + + public: sb4 day_; sb4 hour_; sb4 minute_; diff --git a/odb/oracle/query.hxx b/odb/oracle/query.hxx index a7bacbe..d92296c 100644 --- a/odb/oracle/query.hxx +++ b/odb/oracle/query.hxx @@ -1436,8 +1436,19 @@ namespace odb template struct query_param_impl: query_param { - query_param_impl (ref_bind r) : query_param (&r.ref) {} - query_param_impl (val_bind v) : query_param (0) {init (v.val);} + query_param_impl (ref_bind r) + : query_param (&r.ref), + image_ (descriptor_cache) // Cache, don't free. + { + } + + query_param_impl (val_bind v) + : query_param (0), + image_ (0) // Don't cache, don't free. + + { + init (v.val); + } virtual bool init () @@ -1451,8 +1462,8 @@ namespace odb { b->type = bind_type::timestamp; b->buffer = &image_; - b->capacity = sizeof (image_); - b->size = &size_; + b->capacity = sizeof (OCIDateTime*); + b->size = 0; } private: @@ -1460,18 +1471,105 @@ namespace odb init (const T& v) { bool dummy; - std::size_t size (0); - value_traits::set_image (image_, - size, - sizeof (image_), - dummy, - v); - size_ = static_cast (size); + value_traits::set_image (image_, dummy, v); } private: - char image_[11]; - ub2 size_; + datetime image_; + }; + + // id_interval_ym + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) + : query_param (&r.ref), + image_ (descriptor_cache) // Cache, don't free. + { + } + + query_param_impl (val_bind v) + : query_param (0), + image_ (0) // Don't cache, don't free. + + { + init (v.val); + } + + virtual bool + init () + { + init (*static_cast (value_)); + return false; + } + + virtual void + bind (bind_type* b) + { + b->type = bind_type::interval_ym; + b->buffer = &image_; + b->capacity = sizeof (OCIInterval*); + b->size = 0; + } + + private: + void + init (const T& v) + { + bool dummy; + value_traits::set_image (image_, dummy, v); + } + + private: + interval_ym image_; + }; + + // id_interval_ds + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) + : query_param (&r.ref), + image_ (descriptor_cache) // Cache, don't free. + { + } + + query_param_impl (val_bind v) + : query_param (0), + image_ (0) // Don't cache, don't free. + + { + init (v.val); + } + + virtual bool + init () + { + init (*static_cast (value_)); + return false; + } + + virtual void + bind (bind_type* b) + { + b->type = bind_type::interval_ds; + b->buffer = &image_; + b->capacity = sizeof (OCIInterval*); + b->size = 0; + } + + private: + void + init (const T& v) + { + bool dummy; + value_traits::set_image (image_, dummy, v); + } + + private: + interval_ds image_; }; // id_string. diff --git a/odb/oracle/statement.cxx b/odb/oracle/statement.cxx index d1ab4be..67cec5e 100644 --- a/odb/oracle/statement.cxx +++ b/odb/oracle/statement.cxx @@ -144,18 +144,69 @@ namespace odb (t = conn_.database ().tracer ())) t->deallocate (conn_, *this); } + + // Unbind (free) parameter descriptors. + // + for (size_t i (0); i < usize_; ++i) + { + ub4 t; + bind& b (*udata_[i].bind); + + switch (b.type) + { + case bind::timestamp: + { + datetime* dt (static_cast (b.buffer)); + + if (dt->flags & descriptor_cache) + dt->descriptor = 0; + + t = OCI_DTYPE_TIMESTAMP; + break; + } + case bind::interval_ym: + { + interval_ym* iym (static_cast (b.buffer)); + + if (iym->flags & descriptor_cache) + iym->descriptor = 0; + + t = OCI_DTYPE_INTERVAL_YM; + break; + } + case bind::interval_ds: + { + interval_ds* ids (static_cast (b.buffer)); + + if (ids->flags & descriptor_cache) + ids->descriptor = 0; + + t = OCI_DTYPE_INTERVAL_DS; + break; + } + default: + { + assert (false); + return; + } + } + + OCIDescriptorFree (udata_[i].value, t); + } + + delete[] udata_; } statement:: statement (connection& conn, const string& text) - : conn_ (conn) + : conn_ (conn), udata_ (0), usize_ (0) { init (text.c_str (), text.size ()); } statement:: statement (connection& conn, const char* text) - : conn_ (conn) + : conn_ (conn), udata_ (0), usize_ (0) { init (text, strlen (text)); } @@ -212,6 +263,46 @@ namespace odb void statement:: bind_param (bind* b, size_t n) { + // Figure out how many unbind elements we will need and allocate them. + // + { + size_t un (0); + + for (size_t i (0); i < n; ++i) + { + switch (b[i].type) + { + case bind::timestamp: + { + datetime* dt (static_cast (b[i].buffer)); + if (dt->descriptor == 0 && (dt->flags & descriptor_free) == 0) + un++; + break; + } + case bind::interval_ym: + { + interval_ym* iym (static_cast (b[i].buffer)); + if (iym->descriptor == 0 && (iym->flags & descriptor_free) == 0) + un++; + break; + } + case bind::interval_ds: + { + interval_ds* ids (static_cast (b[i].buffer)); + if (ids->descriptor == 0 && (ids->flags & descriptor_free) == 0) + un++; + break; + } + default: + break; + } + } + + if (un != 0) + udata_ = new unbind[un]; + } + + sword r; OCIError* err (conn_.error_handle ()); OCIEnv* env (conn_.database ().environment ()); @@ -231,75 +322,172 @@ namespace odb { datetime* dt (static_cast (b->buffer)); - if (dt->descriptor.get () == 0) + if (dt->descriptor == 0) { void* d (0); - sword r (OCIDescriptorAlloc (env, - &d, - OCI_DTYPE_TIMESTAMP, - 0, - 0)); + r = OCIDescriptorAlloc (env, + &d, + OCI_DTYPE_TIMESTAMP, + 0, + 0); if (r != OCI_SUCCESS) throw invalid_oci_handle (); - dt->descriptor.reset (static_cast (d)); - dt->environment = env; - dt->error = err; - dt->set (); + if (dt->flags & descriptor_cache) + { + dt->descriptor = static_cast (d); + dt->environment = env; + dt->error = err; + } + + // If the datetime instance is not responsible for the + // descriptor, then we have to arrange to have it freed + // using the unbind machinery. + // + if ((dt->flags & descriptor_free) == 0) + { + unbind& u (udata_[usize_++]); + + u.bind = b; + u.value = d; + value = &u.value; + } + else + value = &dt->descriptor; + + // Initialize the descriptor from the cached data. + // + r = OCIDateTimeConstruct (env, + err, + static_cast (d), + dt->year_, + dt->month_, + dt->day_, + dt->hour_, + dt->minute_, + dt->second_, + dt->nanosecond_, + 0, + 0); + + if (r != OCI_SUCCESS) + translate_error (err, r); } + else + value = &dt->descriptor; - value = &dt->descriptor.get (); break; } case bind::interval_ym: { interval_ym* iym (static_cast (b->buffer)); - if (iym->descriptor.get () == 0) + if (iym->descriptor == 0) { void* d (0); - sword r (OCIDescriptorAlloc (env, - &d, - OCI_DTYPE_INTERVAL_YM, - 0, - 0)); + r = OCIDescriptorAlloc (env, + &d, + OCI_DTYPE_INTERVAL_YM, + 0, + 0); if (r != OCI_SUCCESS) throw invalid_oci_handle (); - iym->descriptor.reset (static_cast (d)); - iym->environment = env; - iym->error = err; - iym->set (); + if (iym->flags & descriptor_cache) + { + iym->descriptor = static_cast (d); + iym->environment = env; + iym->error = err; + } + + // If the interval_ym instance is not responsible for the + // descriptor, then we have to arrange to have it freed + // using the unbind machinery. + // + if ((iym->flags & descriptor_free) == 0) + { + unbind& u (udata_[usize_++]); + + u.bind = b; + u.value = d; + value = &u.value; + } + else + value = &iym->descriptor; + + // Initialize the descriptor from the cached data. + // + r = OCIIntervalSetYearMonth (env, + err, + iym->year_, + iym->month_, + static_cast (d)); + + if (r != OCI_SUCCESS) + translate_error (err, r); } + else + value = &iym->descriptor; - value = &iym->descriptor.get (); break; } case bind::interval_ds: { interval_ds* ids (static_cast (b->buffer)); - if (ids->descriptor.get () == 0) + if (ids->descriptor == 0) { void* d (0); - sword r (OCIDescriptorAlloc (env, - &d, - OCI_DTYPE_INTERVAL_DS, - 0, - 0)); + r = OCIDescriptorAlloc (env, + &d, + OCI_DTYPE_INTERVAL_DS, + 0, + 0); if (r != OCI_SUCCESS) throw invalid_oci_handle (); - ids->descriptor.reset (static_cast (d)); - ids->environment = env; - ids->error = err; - ids->set (); + if (ids->flags & descriptor_cache) + { + ids->descriptor = static_cast (d); + ids->environment = env; + ids->error = err; + } + + // If the interval_ds instance is not responsible for the + // descriptor, then we have to arrange to have it freed + // using the unbind machinery. + // + if ((ids->flags & descriptor_free) == 0) + { + unbind& u (udata_[usize_++]); + + u.bind = b; + u.value = d; + value = &u.value; + } + else + value = &ids->descriptor; + + // Initialize the descriptor from the cached data. + // + r = OCIIntervalSetDaySecond (env, + err, + ids->day_, + ids->hour_, + ids->minute_, + ids->second_, + ids->nanosecond_, + static_cast (d)); + + if (r != OCI_SUCCESS) + translate_error (err, r); } + else + value = &ids->descriptor; - value = &ids->descriptor.get (); break; } case bind::blob: @@ -311,6 +499,11 @@ namespace odb if (lob_buffer.capacity () == 0) lob_buffer.capacity (4096); + // Generally, we should not modify the binding structure or + // image since that would break the thread-safety guarantee + // of the query expression. However, in Oracle, LOBs cannot + // be used in queries so we can make an exception here. + // b->buffer = &lob_buffer; // When binding LOB parameters, the capacity must be greater than @@ -342,20 +535,19 @@ namespace odb } OCIBind* h (0); - - sword r (OCIBindByPos (stmt_, - &h, - err, - i, - value, - static_cast (b->capacity), - param_sqlt_lookup[b->type], - b->indicator, - b->size, - 0, - 0, - 0, - callback ? OCI_DATA_AT_EXEC : OCI_DEFAULT)); + r = OCIBindByPos (stmt_, + &h, + err, + i, + value, + static_cast (b->capacity), + param_sqlt_lookup[b->type], + b->indicator, + b->size, + 0, + 0, + 0, + callback ? OCI_DATA_AT_EXEC : OCI_DEFAULT); if (r == OCI_ERROR || r == OCI_INVALID_HANDLE) translate_error (err, r); @@ -392,6 +584,7 @@ namespace odb { ODB_POTENTIALLY_UNUSED (p); + sword r; OCIError* err (conn_.error_handle ()); OCIEnv* env (conn_.database ().environment ()); @@ -406,72 +599,81 @@ namespace odb { datetime* dt (static_cast (b->buffer)); - if (dt->descriptor.get () == 0) + if (dt->descriptor == 0) { + assert ((dt->flags & descriptor_cache) && + (dt->flags & descriptor_free)); + void* d (0); - sword r (OCIDescriptorAlloc (env, - &d, - OCI_DTYPE_TIMESTAMP, - 0, - 0)); + r = OCIDescriptorAlloc (env, + &d, + OCI_DTYPE_TIMESTAMP, + 0, + 0); if (r != OCI_SUCCESS) throw invalid_oci_handle (); - dt->descriptor.reset (static_cast (d)); + dt->descriptor = static_cast (d); dt->environment = env; dt->error = err; } - value = &dt->descriptor.get (); + value = &dt->descriptor; break; } case bind::interval_ym: { interval_ym* iym (static_cast (b->buffer)); - if (iym->descriptor.get () == 0) + if (iym->descriptor == 0) { + assert ((iym->flags & descriptor_cache) && + (iym->flags & descriptor_free)); + void* d (0); - sword r (OCIDescriptorAlloc (env, - &d, - OCI_DTYPE_INTERVAL_YM, - 0, - 0)); + r = OCIDescriptorAlloc (env, + &d, + OCI_DTYPE_INTERVAL_YM, + 0, + 0); if (r != OCI_SUCCESS) throw invalid_oci_handle (); - iym->descriptor.reset (static_cast (d)); + iym->descriptor = static_cast (d); iym->environment = env; iym->error = err; } - value = &iym->descriptor.get (); + value = &iym->descriptor; break; } case bind::interval_ds: { interval_ds* ids (static_cast (b->buffer)); - if (ids->descriptor.get () == 0) + if (ids->descriptor == 0) { + assert ((ids->flags & descriptor_cache) && + (ids->flags & descriptor_free)); + void* d (0); - sword r (OCIDescriptorAlloc (env, - &d, - OCI_DTYPE_INTERVAL_DS, - 0, - 0)); + r = OCIDescriptorAlloc (env, + &d, + OCI_DTYPE_INTERVAL_DS, + 0, + 0); if (r != OCI_SUCCESS) throw invalid_oci_handle (); - ids->descriptor.reset (static_cast (d)); + ids->descriptor = static_cast (d); ids->environment = env; ids->error = err; } - value = &ids->descriptor.get (); + value = &ids->descriptor; break; } case bind::blob: @@ -484,7 +686,7 @@ namespace odb if (lob->get () == 0) { void* d (0); - sword r (OCIDescriptorAlloc (env, &d, OCI_DTYPE_LOB, 0, 0)); + r = OCIDescriptorAlloc (env, &d, OCI_DTYPE_LOB, 0, 0); if (r != OCI_SUCCESS) throw invalid_oci_handle (); @@ -514,17 +716,17 @@ namespace odb } OCIDefine* h (0); - sword r (OCIDefineByPos (stmt_, - &h, - err, - i, - value, - static_cast (b->capacity), - result_sqlt_lookup[b->type], - b->indicator, - size, - 0, - OCI_DEFAULT)); + r = OCIDefineByPos (stmt_, + &h, + err, + i, + value, + static_cast (b->capacity), + result_sqlt_lookup[b->type], + b->indicator, + size, + 0, + OCI_DEFAULT); if (r == OCI_ERROR || r == OCI_INVALID_HANDLE) translate_error (err, r); @@ -584,6 +786,7 @@ namespace odb { ODB_POTENTIALLY_UNUSED (p); + sword r; OCIEnv* env (conn_.database ().environment ()); for (size_t i (1); i <= c; ++i, ++b) @@ -596,66 +799,66 @@ namespace odb { datetime* dt (static_cast (b->buffer)); - if (dt->descriptor.get () == 0) + if (dt->descriptor == 0) { void* d (0); - sword r (OCIDescriptorAlloc (env, - &d, - OCI_DTYPE_TIMESTAMP, - 0, - 0)); + r = OCIDescriptorAlloc (env, + &d, + OCI_DTYPE_TIMESTAMP, + 0, + 0); if (r != OCI_SUCCESS) throw invalid_oci_handle (); - dt->descriptor.reset (static_cast (d)); + dt->descriptor = static_cast (d); } - value = &dt->descriptor.get (); + value = &dt->descriptor; break; } case bind::interval_ym: { interval_ym* iym (static_cast (b->buffer)); - if (iym->descriptor.get () == 0) + if (iym->descriptor == 0) { void* d (0); - sword r (OCIDescriptorAlloc (env, - &d, - OCI_DTYPE_INTERVAL_YM, - 0, - 0)); + r = OCIDescriptorAlloc (env, + &d, + OCI_DTYPE_INTERVAL_YM, + 0, + 0); if (r != OCI_SUCCESS) throw invalid_oci_handle (); - iym->descriptor.reset (static_cast (d)); + iym->descriptor = static_cast (d); } - value = &iym->descriptor.get (); + value = &iym->descriptor; break; } case bind::interval_ds: { interval_ds* ids (static_cast (b->buffer)); - if (ids->descriptor.get () == 0) + if (ids->descriptor == 0) { void* d (0); - sword r (OCIDescriptorAlloc (env, - &d, - OCI_DTYPE_INTERVAL_DS, - 0, - 0)); + r = OCIDescriptorAlloc (env, + &d, + OCI_DTYPE_INTERVAL_DS, + 0, + 0); if (r != OCI_SUCCESS) throw invalid_oci_handle (); - ids->descriptor.reset (static_cast (d)); + ids->descriptor = static_cast (d); } - value = &ids->descriptor.get (); + value = &ids->descriptor; break; } case bind::blob: @@ -668,7 +871,7 @@ namespace odb if (lob->get () == 0) { void* d (0); - sword r (OCIDescriptorAlloc (env, &d, OCI_DTYPE_LOB, 0, 0)); + r = OCIDescriptorAlloc (env, &d, OCI_DTYPE_LOB, 0, 0); if (r != OCI_SUCCESS) throw invalid_oci_handle (); @@ -692,17 +895,17 @@ namespace odb OCIDefine* h (reinterpret_cast (b->size)); OCIError* err (conn_.error_handle ()); - sword r (OCIDefineByPos (stmt_, - &h, - err, - i, - value, - static_cast (b->capacity), - result_sqlt_lookup[b->type], - b->indicator, - 0, - 0, - OCI_DEFAULT)); + r = OCIDefineByPos (stmt_, + &h, + err, + i, + value, + static_cast (b->capacity), + result_sqlt_lookup[b->type], + b->indicator, + 0, + 0, + OCI_DEFAULT); if (r == OCI_ERROR || r == OCI_INVALID_HANDLE) translate_error (err, r); diff --git a/odb/oracle/statement.hxx b/odb/oracle/statement.hxx index 8d97ab4..3687728 100644 --- a/odb/oracle/statement.hxx +++ b/odb/oracle/statement.hxx @@ -50,6 +50,12 @@ namespace odb init (const char* text, std::size_t text_size); protected: + struct unbind + { + oracle::bind* bind; // Corresponding bind entry. + void* value; // Actual value passed to OCIBindByPos. + }; + // Bind parameters for this statement. This function must only // be called once. Multiple calls to it will result in memory // leaks due to lost OCIBind resources. @@ -85,6 +91,9 @@ namespace odb protected: connection& conn_; auto_handle stmt_; + + unbind* udata_; + std::size_t usize_; }; class LIBODB_ORACLE_EXPORT generic_statement: public statement -- cgit v1.1