aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2011-11-10 16:23:24 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2011-11-10 16:28:29 +0200
commit0fb66e3e85ccb096cb625bf4664fdbbf3b8a29f9 (patch)
tree6ee6a9fce07ecc686afefd7aa8f83b5e57fd2a30
parentf5f1489bed3bddd424981bbe84898832fb0e7414 (diff)
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.
-rw-r--r--odb/oracle/oracle-types.cxx197
-rw-r--r--odb/oracle/oracle-types.hxx146
-rw-r--r--odb/oracle/query.hxx124
-rw-r--r--odb/oracle/statement.cxx445
-rw-r--r--odb/oracle/statement.hxx9
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<OCIDateTime, dt_timestamp>
- {
- typedef auto_descriptor<OCIDateTime, dt_timestamp> 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<OCIInterval, dt_interval_ym>
- {
- typedef auto_descriptor<OCIInterval, dt_interval_ym> 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<OCIInterval, dt_interval_ds>
- {
- typedef auto_descriptor<OCIInterval, dt_interval_ds> 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 <typename T>
struct query_param_impl<T, id_timestamp>: query_param
{
- query_param_impl (ref_bind<T> r) : query_param (&r.ref) {}
- query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);}
+ query_param_impl (ref_bind<T> r)
+ : query_param (&r.ref),
+ image_ (descriptor_cache) // Cache, don't free.
+ {
+ }
+
+ query_param_impl (val_bind<T> 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<T, id_timestamp>::set_image (image_,
- size,
- sizeof (image_),
- dummy,
- v);
- size_ = static_cast<ub2> (size);
+ value_traits<T, id_timestamp>::set_image (image_, dummy, v);
}
private:
- char image_[11];
- ub2 size_;
+ datetime image_;
+ };
+
+ // id_interval_ym
+ //
+ template <typename T>
+ struct query_param_impl<T, id_interval_ym>: query_param
+ {
+ query_param_impl (ref_bind<T> r)
+ : query_param (&r.ref),
+ image_ (descriptor_cache) // Cache, don't free.
+ {
+ }
+
+ query_param_impl (val_bind<T> v)
+ : query_param (0),
+ image_ (0) // Don't cache, don't free.
+
+ {
+ init (v.val);
+ }
+
+ virtual bool
+ init ()
+ {
+ init (*static_cast<const T*> (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<T, id_interval_ym>::set_image (image_, dummy, v);
+ }
+
+ private:
+ interval_ym image_;
+ };
+
+ // id_interval_ds
+ //
+ template <typename T>
+ struct query_param_impl<T, id_interval_ds>: query_param
+ {
+ query_param_impl (ref_bind<T> r)
+ : query_param (&r.ref),
+ image_ (descriptor_cache) // Cache, don't free.
+ {
+ }
+
+ query_param_impl (val_bind<T> v)
+ : query_param (0),
+ image_ (0) // Don't cache, don't free.
+
+ {
+ init (v.val);
+ }
+
+ virtual bool
+ init ()
+ {
+ init (*static_cast<const T*> (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<T, id_interval_ds>::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<datetime*> (b.buffer));
+
+ if (dt->flags & descriptor_cache)
+ dt->descriptor = 0;
+
+ t = OCI_DTYPE_TIMESTAMP;
+ break;
+ }
+ case bind::interval_ym:
+ {
+ interval_ym* iym (static_cast<interval_ym*> (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<interval_ds*> (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<datetime*> (b[i].buffer));
+ if (dt->descriptor == 0 && (dt->flags & descriptor_free) == 0)
+ un++;
+ break;
+ }
+ case bind::interval_ym:
+ {
+ interval_ym* iym (static_cast<interval_ym*> (b[i].buffer));
+ if (iym->descriptor == 0 && (iym->flags & descriptor_free) == 0)
+ un++;
+ break;
+ }
+ case bind::interval_ds:
+ {
+ interval_ds* ids (static_cast<interval_ds*> (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<datetime*> (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<OCIDateTime*> (d));
- dt->environment = env;
- dt->error = err;
- dt->set ();
+ if (dt->flags & descriptor_cache)
+ {
+ dt->descriptor = static_cast<OCIDateTime*> (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<OCIDateTime*> (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<interval_ym*> (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<OCIInterval*> (d));
- iym->environment = env;
- iym->error = err;
- iym->set ();
+ if (iym->flags & descriptor_cache)
+ {
+ iym->descriptor = static_cast<OCIInterval*> (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<OCIInterval*> (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<interval_ds*> (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<OCIInterval*> (d));
- ids->environment = env;
- ids->error = err;
- ids->set ();
+ if (ids->flags & descriptor_cache)
+ {
+ ids->descriptor = static_cast<OCIInterval*> (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<OCIInterval*> (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<sb4> (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<sb4> (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<datetime*> (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<OCIDateTime*> (d));
+ dt->descriptor = static_cast<OCIDateTime*> (d);
dt->environment = env;
dt->error = err;
}
- value = &dt->descriptor.get ();
+ value = &dt->descriptor;
break;
}
case bind::interval_ym:
{
interval_ym* iym (static_cast<interval_ym*> (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<OCIInterval*> (d));
+ iym->descriptor = static_cast<OCIInterval*> (d);
iym->environment = env;
iym->error = err;
}
- value = &iym->descriptor.get ();
+ value = &iym->descriptor;
break;
}
case bind::interval_ds:
{
interval_ds* ids (static_cast<interval_ds*> (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<OCIInterval*> (d));
+ ids->descriptor = static_cast<OCIInterval*> (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<sb4> (b->capacity),
- result_sqlt_lookup[b->type],
- b->indicator,
- size,
- 0,
- OCI_DEFAULT));
+ r = OCIDefineByPos (stmt_,
+ &h,
+ err,
+ i,
+ value,
+ static_cast<sb4> (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<datetime*> (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<OCIDateTime*> (d));
+ dt->descriptor = static_cast<OCIDateTime*> (d);
}
- value = &dt->descriptor.get ();
+ value = &dt->descriptor;
break;
}
case bind::interval_ym:
{
interval_ym* iym (static_cast<interval_ym*> (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<OCIInterval*> (d));
+ iym->descriptor = static_cast<OCIInterval*> (d);
}
- value = &iym->descriptor.get ();
+ value = &iym->descriptor;
break;
}
case bind::interval_ds:
{
interval_ds* ids (static_cast<interval_ds*> (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<OCIInterval*> (d));
+ ids->descriptor = static_cast<OCIInterval*> (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<OCIDefine*> (b->size));
OCIError* err (conn_.error_handle ());
- sword r (OCIDefineByPos (stmt_,
- &h,
- err,
- i,
- value,
- static_cast<sb4> (b->capacity),
- result_sqlt_lookup[b->type],
- b->indicator,
- 0,
- 0,
- OCI_DEFAULT));
+ r = OCIDefineByPos (stmt_,
+ &h,
+ err,
+ i,
+ value,
+ static_cast<sb4> (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<OCIStmt> stmt_;
+
+ unbind* udata_;
+ std::size_t usize_;
};
class LIBODB_ORACLE_EXPORT generic_statement: public statement