aboutsummaryrefslogtreecommitdiff
path: root/odb/oracle/statement.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'odb/oracle/statement.cxx')
-rw-r--r--odb/oracle/statement.cxx445
1 files changed, 324 insertions, 121 deletions
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);