summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorConstantin Michael <constantin@codesynthesis.com>2011-11-07 15:02:14 +0200
committerConstantin Michael <constantin@codesynthesis.com>2011-11-08 14:46:33 +0200
commit655fc5c0827d56b6eaa86f80c904d9a607530fcb (patch)
treecf4679282bb15dd15c73ff429e0b20428eb58650
parent60d4d13a85130ccdc3b232e420bc3c18683846b9 (diff)
Implement support for Oracle temporal types
-rw-r--r--odb/oracle/auto-descriptor.cxx16
-rw-r--r--odb/oracle/auto-descriptor.hxx63
-rw-r--r--odb/oracle/details/date.hxx61
-rw-r--r--odb/oracle/makefile1
-rw-r--r--odb/oracle/oracle-fwd.hxx5
-rw-r--r--odb/oracle/oracle-types.cxx135
-rw-r--r--odb/oracle/oracle-types.hxx213
-rw-r--r--odb/oracle/statement.cxx562
-rw-r--r--odb/oracle/traits.hxx28
9 files changed, 865 insertions, 219 deletions
diff --git a/odb/oracle/auto-descriptor.cxx b/odb/oracle/auto-descriptor.cxx
index 522d1e9..b332c16 100644
--- a/odb/oracle/auto-descriptor.cxx
+++ b/odb/oracle/auto-descriptor.cxx
@@ -11,13 +11,19 @@ namespace odb
{
namespace oracle
{
+ static const ub4 oci_descriptor_types[] =
+ {
+ OCI_DTYPE_PARAM,
+ OCI_DTYPE_LOB,
+ OCI_DTYPE_TIMESTAMP,
+ OCI_DTYPE_INTERVAL_YM,
+ OCI_DTYPE_INTERVAL_DS
+ };
+
void
- oci_descriptor_free (void* d, ub4 type)
+ oci_descriptor_free (void* d, descriptor_type type)
{
- OCIDescriptorFree (d, type);
+ OCIDescriptorFree (d, oci_descriptor_types[type - 1]);
}
-
- const ub4 descriptor_type_traits<OCIParam>::dtype = OCI_DTYPE_PARAM;
- const ub4 descriptor_type_traits<OCILobLocator>::dtype = OCI_DTYPE_LOB;
}
}
diff --git a/odb/oracle/auto-descriptor.hxx b/odb/oracle/auto-descriptor.hxx
index f55925d..6bc97d6 100644
--- a/odb/oracle/auto-descriptor.hxx
+++ b/odb/oracle/auto-descriptor.hxx
@@ -17,41 +17,64 @@ namespace odb
{
namespace oracle
{
+ enum descriptor_type
+ {
+ dt_default = 0,
+ dt_param,
+ dt_lob,
+ dt_timestamp,
+ dt_interval_ym,
+ dt_interval_ds
+ };
+
+ LIBODB_ORACLE_EXPORT void
+ oci_descriptor_free (void* descriptor, descriptor_type type);
+
//
// descriptor_type_traits
//
template <typename D>
- struct descriptor_type_traits;
+ struct default_descriptor_type_traits;
template <>
- struct descriptor_type_traits<OCIParam>
- { static const ub4 dtype; };
+ struct default_descriptor_type_traits<OCIParam>
+ { static const descriptor_type dtype = dt_param; };
template <>
- struct descriptor_type_traits<OCILobLocator>
- { static const ub4 dtype; };
-
+ struct default_descriptor_type_traits<OCILobLocator>
+ { static const descriptor_type dtype = dt_lob; };
//
- // descriptor_traits
+ // auto_descriptor_base
//
- LIBODB_ORACLE_EXPORT void
- oci_descriptor_free (void* descriptor, ub4 type);
+ template <typename D, descriptor_type Type>
+ struct auto_descriptor_base
+ {
+ static void
+ release (D* d)
+ {
+ oci_descriptor_free (d, Type);
+ }
+ };
template <typename D>
- struct descriptor_traits
+ struct auto_descriptor_base<D, dt_default>
{
static void
release (D* d)
{
- oci_descriptor_free (d, descriptor_type_traits<D>::dtype);
+ oci_descriptor_free (d, default_descriptor_type_traits<D>::dtype);
}
};
- template <typename D>
- class auto_descriptor
+ //
+ // auto_descriptor
+ //
+
+ template <typename D, descriptor_type T = dt_default>
+ class auto_descriptor: auto_descriptor_base<D, T>
{
public:
auto_descriptor (D* d = 0)
@@ -62,25 +85,31 @@ namespace odb
~auto_descriptor ()
{
if (d_ != 0)
- descriptor_traits<D>::release (d_);
+ release (d_);
}
- operator D* ()
+ operator D* () const
{
return d_;
}
- D*
+ D*&
get ()
{
return d_;
}
+ D*
+ get () const
+ {
+ return d_;
+ }
+
void
reset (D* d = 0)
{
if (d_ != 0)
- descriptor_traits<D>::release (d_);
+ release (d_);
d_ = d;
}
diff --git a/odb/oracle/details/date.hxx b/odb/oracle/details/date.hxx
new file mode 100644
index 0000000..47137f6
--- /dev/null
+++ b/odb/oracle/details/date.hxx
@@ -0,0 +1,61 @@
+// file : odb/oracle/details/date.hxx
+// author : Constantin Michael <constantin@codesynthesis.com>
+// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC
+// license : ODB NCUEL; see accompanying LICENSE file
+
+#ifndef ODB_ORACLE_DETAILS_DATE_HXX
+#define ODB_ORACLE_DETAILS_DATE_HXX
+
+namespace odb
+{
+ // @@ Revise this.
+ //
+ namespace details
+ {
+ }
+
+ namespace oracle
+ {
+ namespace details
+ {
+ inline void
+ set_date (char* b,
+ short year,
+ unsigned char month,
+ unsigned char day,
+ unsigned char hour,
+ unsigned char minute,
+ unsigned char second)
+ {
+ b[0] = static_cast<char> (year / 100 + 100);
+ b[1] = static_cast<char> (year % 100 + 100);
+ b[2] = static_cast<char> (month);
+ b[3] = static_cast<char> (day);
+ b[4] = static_cast<char> (hour + 1);
+ b[5] = static_cast<char> (minute + 1);
+ b[6] = static_cast<char> (second + 1);
+ }
+
+ inline void
+ get_date (short& year,
+ unsigned char& month,
+ unsigned char& day,
+ unsigned char& hour,
+ unsigned char& minute,
+ unsigned char& second,
+ const char* b)
+ {
+ const unsigned char* ub (reinterpret_cast<const unsigned char*> (b));
+
+ year = 100 * ub[0] + ub[1] - 10100;
+ month = ub[2];
+ day = ub[3];
+ hour = ub[4] - 1;
+ minute = ub[5] - 1;
+ second = ub[6] - 1;
+ }
+ }
+ }
+}
+
+#endif // ODB_ORACLE_DETAILS_DATE_HXX
diff --git a/odb/oracle/makefile b/odb/oracle/makefile
index cf1db15..f173b95 100644
--- a/odb/oracle/makefile
+++ b/odb/oracle/makefile
@@ -14,6 +14,7 @@ database.cxx \
error.cxx \
exceptions.cxx \
object-statements.cxx \
+oracle-types.cxx \
query.cxx \
query-const-expr.cxx \
statement.cxx \
diff --git a/odb/oracle/oracle-fwd.hxx b/odb/oracle/oracle-fwd.hxx
index 813414c..dee5736 100644
--- a/odb/oracle/oracle-fwd.hxx
+++ b/odb/oracle/oracle-fwd.hxx
@@ -12,6 +12,9 @@
// allows us to avoid having to include oci.h in public headers.
//
typedef signed int sword;
+
+typedef unsigned char ub1;
+typedef signed char sb1;
typedef signed short sb2;
typedef unsigned short ub2;
typedef signed int sb4;
@@ -26,6 +29,8 @@ typedef struct OCITrans OCITrans;
typedef struct OCIParam OCIParam;
typedef struct OCILobLocator OCILobLocator;
+typedef struct OCIDateTime OCIDateTime;
+typedef struct OCIInterval OCIInterval;
#include <odb/post.hxx>
diff --git a/odb/oracle/oracle-types.cxx b/odb/oracle/oracle-types.cxx
new file mode 100644
index 0000000..17ae479
--- /dev/null
+++ b/odb/oracle/oracle-types.cxx
@@ -0,0 +1,135 @@
+// file : odb/oracle/oracle-types.hxx
+// author : Constantin Michael <constantin@codesynthesis.com>
+// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC
+// license : ODB NCUEL; see accompanying LICENSE file
+
+#include <cassert>
+
+#include <oci.h>
+
+#include <odb/oracle/oracle-types.hxx>
+#include <odb/oracle/error.hxx>
+
+namespace odb
+{
+ namespace oracle
+ {
+ void datetime::
+ get () const
+ {
+ assert (descriptor.get () != 0);
+
+ sword r (OCIDateTimeGetDate (descriptor.environment,
+ descriptor.error,
+ descriptor,
+ &fields.year,
+ &fields.month,
+ &fields.day));
+
+ if (r != OCI_SUCCESS)
+ translate_error (descriptor.error, r);
+
+ r = OCIDateTimeGetTime (descriptor.environment,
+ descriptor.error,
+ descriptor,
+ &fields.hour,
+ &fields.minute,
+ &fields.second,
+ &fields.nanosecond);
+
+ if (r != OCI_SUCCESS)
+ translate_error (descriptor.error, r);
+ }
+
+ void datetime::
+ set ()
+ {
+ if (descriptor.get () != 0)
+ {
+ sword r (OCIDateTimeConstruct (descriptor.environment,
+ descriptor.error,
+ descriptor,
+ fields.year,
+ fields.month,
+ fields.day,
+ fields.hour,
+ fields.minute,
+ fields.second,
+ fields.nanosecond,
+ 0,
+ 0));
+
+ if (r != OCI_SUCCESS)
+ translate_error (descriptor.error, r);
+ }
+ }
+
+ void interval_ym::
+ get () const
+ {
+ assert (descriptor.get () != 0);
+
+ sword r (OCIIntervalGetYearMonth (descriptor.environment,
+ descriptor.error,
+ &fields.year,
+ &fields.month,
+ descriptor));
+
+ if (r != OCI_SUCCESS)
+ translate_error (descriptor.error, r);
+ }
+
+ void interval_ym::
+ set ()
+ {
+ if (descriptor.get () != 0)
+ {
+ sword r (OCIIntervalSetYearMonth (descriptor.environment,
+ descriptor.error,
+ fields.year,
+ fields.month,
+ descriptor));
+
+ if (r != OCI_SUCCESS)
+ translate_error (descriptor.error, r);
+ }
+ }
+
+ void interval_ds::
+ get () const
+ {
+ assert (descriptor.get () != 0);
+
+ sword r (OCIIntervalGetDaySecond (descriptor.environment,
+ descriptor.error,
+ &fields.day,
+ &fields.hour,
+ &fields.minute,
+ &fields.second,
+ &fields.nanosecond,
+ descriptor));
+
+ if (r != OCI_SUCCESS)
+ translate_error (descriptor.error, r);
+ }
+
+ void interval_ds::
+ set ()
+ {
+ if (descriptor.get () != 0)
+ {
+ sword r (OCIIntervalSetDaySecond (descriptor.environment,
+ descriptor.error,
+ fields.day,
+ fields.hour,
+ fields.minute,
+ fields.second,
+ fields.nanosecond,
+ descriptor));
+
+ if (r != OCI_SUCCESS)
+ translate_error (descriptor.error, r);
+ }
+ }
+ }
+}
diff --git a/odb/oracle/oracle-types.hxx b/odb/oracle/oracle-types.hxx
index 3327c57..f12caeb 100644
--- a/odb/oracle/oracle-types.hxx
+++ b/odb/oracle/oracle-types.hxx
@@ -90,7 +90,9 @@ namespace odb
binary_double, // Buffer is a double.
number, // Buffer is a variable length char array.
date, // Buffer is a 7-byte char array.
- timestamp, // Buffer is a variable length char array.
+ timestamp, // Buffer is a datetime.
+ interval_ym, // Buffer is an interval_ym.
+ interval_ds, // Buffer is an interval_ds.
string, // Buffer is a variable length char array.
nstring, // Buffer is a variable length char array.
raw, // Buffer is a variable length char array.
@@ -132,22 +134,28 @@ namespace odb
void* context;
};
- // The LOB specialization of auto_descriptor allows for transparent
- // transferal of LOB descriptors between auto_descriptor instances. This
+ //
+ // These specialized auto_descriptor classes allows for transparent
+ // transferal of descriptors between auto_descriptor instances. This
// simplifies the implementation of a private copy of the shared image
- // associated with queries.
+ // associated with queries. The specializations for OCIDateTime and
+ // OCIInterval also wrap OCI handles that are required for manipulation
+ // of the descriptor data.
//
- class LIBODB_ORACLE_EXPORT lob_auto_descriptor
- : auto_descriptor<OCILobLocator>
+
+ class LIBODB_ORACLE_EXPORT lob_auto_descriptor:
+ public auto_descriptor<OCILobLocator>
{
+ typedef auto_descriptor <OCILobLocator> base;
+
public:
lob_auto_descriptor (OCILobLocator* l = 0)
- : auto_descriptor<OCILobLocator> (l)
+ : base (l)
{
}
lob_auto_descriptor (lob_auto_descriptor& x)
- : auto_descriptor<OCILobLocator> (x.d_)
+ : base (x.d_)
{
x.d_ = 0;
}
@@ -162,6 +170,195 @@ namespace odb
return *this;
}
};
+
+ 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),
+ environment (0),
+ error (0)
+ {
+ }
+
+ datetime_auto_descriptor (datetime_auto_descriptor& x):
+ base (x.d_),
+ environment (x.environment),
+ error (x.error)
+ {
+ x.d_ = 0;
+ }
+
+ datetime_auto_descriptor&
+ operator= (datetime_auto_descriptor& x)
+ {
+ OCIDateTime* l (x.d_);
+ x.d_ = 0;
+ reset (l);
+
+ environment = x.environment;
+ error = x.error;
+
+ return *this;
+ }
+
+ OCIEnv* environment;
+ OCIError* error;
+ };
+
+ 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),
+ environment (0),
+ error (0)
+ {
+ }
+
+ interval_ym_auto_descriptor (interval_ym_auto_descriptor& x):
+ base (x.d_),
+ environment (x.environment),
+ error (x.error)
+ {
+ x.d_ = 0;
+ }
+
+ interval_ym_auto_descriptor&
+ operator= (interval_ym_auto_descriptor& x)
+ {
+ OCIInterval* l (x.d_);
+ x.d_ = 0;
+ reset (l);
+
+ environment = x.environment;
+ error = x.error;
+
+ return *this;
+ }
+
+ OCIEnv* environment;
+ OCIError* error;
+ };
+
+ 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),
+ environment (0),
+ error (0)
+ {
+ }
+
+ interval_ds_auto_descriptor (interval_ds_auto_descriptor& x):
+ base (x.d_),
+ environment (x.environment),
+ error (x.error)
+ {
+ x.d_ = 0;
+ }
+
+ interval_ds_auto_descriptor&
+ operator= (interval_ds_auto_descriptor& x)
+ {
+ OCIInterval* l (x.d_);
+ x.d_ = 0;
+ reset (l);
+
+ environment = x.environment;
+ error = x.error;
+
+ return *this;
+ }
+
+ OCIEnv* environment;
+ OCIError* error;
+ };
+
+ //
+ // The OCIDateTime and OCIInterval APIs require that an environment and
+ // error handle be passed any function that manipulates an OCIDateTime or
+ // OCIInterval descriptor. It is however impossible to obtain these handles
+ // the first time any temporal data image is initialized. The following
+ // structures allow ODB generated code to interact with the OCI temporal
+ // descriptor types indirectly via C++ primitives. The wrapped OCI
+ // descriptor is then set using these primitives at a time when the all the
+ // required data is available. A symmetric get interface is provided for
+ // consistency.
+ //
+
+ struct LIBODB_ORACLE_EXPORT datetime
+ {
+ struct fields_type
+ {
+ sb2 year;
+ ub1 month;
+ ub1 day;
+ ub1 hour;
+ ub1 minute;
+ ub1 second;
+ ub4 nanosecond;
+ };
+
+ mutable fields_type fields;
+ datetime_auto_descriptor descriptor;
+
+ void
+ get () const;
+
+ void
+ set ();
+
+ };
+
+ struct LIBODB_ORACLE_EXPORT interval_ym
+ {
+ struct fields_type
+ {
+ sb4 year;
+ sb4 month;
+ };
+
+ mutable fields_type fields;
+ interval_ym_auto_descriptor descriptor;
+
+ void
+ get () const;
+
+ void
+ set ();
+ };
+
+ struct LIBODB_ORACLE_EXPORT interval_ds
+ {
+ struct fields_type
+ {
+ sb4 day;
+ sb4 hour;
+ sb4 minute;
+ sb4 second;
+ sb4 nanosecond;
+ };
+
+ mutable fields_type fields;
+ interval_ds_auto_descriptor descriptor;
+
+ void
+ get () const;
+
+ void
+ set ();
+ };
}
}
diff --git a/odb/oracle/statement.cxx b/odb/oracle/statement.cxx
index c1747a3..efbaf72 100644
--- a/odb/oracle/statement.cxx
+++ b/odb/oracle/statement.cxx
@@ -27,41 +27,45 @@ namespace odb
// Mapping of bind::buffer_type values for parameter buffers to their
// equivalent external OCI typecode identifiers.
//
- static ub4 param_sqlt_lookup[bind::last] =
+ static const ub4 param_sqlt_lookup[bind::last] =
{
- SQLT_INT, // bind::integer
- SQLT_UIN, // bind::uinteger
- SQLT_BFLOAT, // bind::binary_float
- SQLT_BDOUBLE, // bind::binary_double
- SQLT_NUM, // bind::number
- SQLT_DAT, // bind::date
- SQLT_TIMESTAMP, // bind::timestamp
- SQLT_CHR, // bind::string
- SQLT_CHR, // bind::nstring
- SQLT_BIN, // bind::raw
- SQLT_LBI, // bind::blob
- SQLT_LNG, // bind::clob
- SQLT_LNG // bind::nclob
+ SQLT_INT, // bind::integer
+ SQLT_UIN, // bind::uinteger
+ SQLT_BFLOAT, // bind::binary_float
+ SQLT_BDOUBLE, // bind::binary_double
+ SQLT_NUM, // bind::number
+ SQLT_DAT, // bind::date
+ SQLT_TIMESTAMP, // bind::timestamp
+ SQLT_INTERVAL_YM, // bind::interval_ym
+ SQLT_INTERVAL_DS, // bind::interval_ds
+ SQLT_CHR, // bind::string
+ SQLT_CHR, // bind::nstring
+ SQLT_BIN, // bind::raw
+ SQLT_LBI, // bind::blob
+ SQLT_LNG, // bind::clob
+ SQLT_LNG // bind::nclob
};
// Mapping of bind::buffer_type values for result buffers to their
// equivalent external OCI typecode identifiers.
//
- static ub4 result_sqlt_lookup[bind::last] =
+ static const ub4 result_sqlt_lookup[bind::last] =
{
- SQLT_INT, // bind::integer
- SQLT_UIN, // bind::uinteger
- SQLT_BFLOAT, // bind::binary_float
- SQLT_BDOUBLE, // bind::binary_double
- SQLT_NUM, // bind::number
- SQLT_DAT, // bind::date
- SQLT_TIMESTAMP, // bind::timestamp
- SQLT_CHR, // bind::string
- SQLT_CHR, // bind::nstring
- SQLT_BIN, // bind::raw
- SQLT_BLOB, // bind::blob
- SQLT_CLOB, // bind::clob
- SQLT_CLOB // bind::nclob
+ SQLT_INT, // bind::integer
+ SQLT_UIN, // bind::uinteger
+ SQLT_BFLOAT, // bind::binary_float
+ SQLT_BDOUBLE, // bind::binary_double
+ SQLT_NUM, // bind::number
+ SQLT_DAT, // bind::date
+ SQLT_TIMESTAMP, // bind::timestamp
+ SQLT_INTERVAL_YM, // bind::interval_ym
+ SQLT_INTERVAL_DS, // bind::interval_ds
+ SQLT_CHR, // bind::string
+ SQLT_CHR, // bind::nstring
+ SQLT_BIN, // bind::raw
+ SQLT_BLOB, // bind::blob
+ SQLT_CLOB, // bind::clob
+ SQLT_CLOB // bind::nclob
};
static sb4
@@ -156,41 +160,139 @@ namespace odb
bind_param (bind* b, size_t n)
{
OCIError* err (conn_.error_handle ());
+ OCIEnv* env (conn_.database ().environment ());
// The parameter position in OCIBindByPos is specified as a 1-based
// index.
//
n++;
+
for (ub4 i (1); i < n; ++i, ++b)
{
-#if OCI_MAJOR_VERSION < 11 || \
+ void* value (0);
+ bool callback (b->callback != 0);
+
+ switch (b->type)
+ {
+ case bind::timestamp:
+ {
+ datetime* dt (static_cast<datetime*> (b->buffer));
+
+ if (dt->descriptor.get () == 0)
+ {
+ void* d (0);
+ sword 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.environment = env;
+ dt->descriptor.error = err;
+ dt->set ();
+ }
+
+ value = &dt->descriptor.get ();
+ break;
+ }
+ case bind::interval_ym:
+ {
+ interval_ym* iym (static_cast<interval_ym*> (b->buffer));
+
+ if (iym->descriptor.get () == 0)
+ {
+ void* d (0);
+ sword 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.environment = env;
+ iym->descriptor.error = err;
+ iym->set ();
+ }
+
+ value = &iym->descriptor.get ();
+ break;
+ }
+ case bind::interval_ds:
+ {
+ interval_ds* ids (static_cast<interval_ds*> (b->buffer));
+
+ if (ids->descriptor.get () == 0)
+ {
+ void* d (0);
+ sword 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.environment = env;
+ ids->descriptor.error = err;
+ ids->set ();
+ }
+
+ value = &ids->descriptor.get ();
+ break;
+ }
+ case bind::blob:
+ case bind::clob:
+ case bind::nclob:
+ {
+ details::buffer& lob_buffer (conn_.lob_buffer ());
+
+ if (lob_buffer.capacity () == 0)
+ lob_buffer.capacity (4096);
+
+ b->buffer = &lob_buffer;
+
+ break;
+ }
+ default:
+ {
+#if OCI_MAJOR_VERSION < 11 || \
(OCI_MAJOR_VERSION == 11 && OCI_MINOR_VERSION < 2)
- // Assert if a 64 bit integer buffer type is provided and the OCI
- // version is unable to implicitly convert the NUMBER binary data
- // to the relevant type.
- //
- assert ((b->type != bind::integer && b->type != bind::uinteger) ||
- b->capacity <= 4);
+ // Assert if a 64 bit integer buffer type is provided and the OCI
+ // version is unable to implicitly convert the NUMBER binary data
+ // to the relevant type.
+ //
+ assert ((b->type != bind::integer &&
+ b->type != bind::uinteger) || b->capacity <= 4);
#endif
+ if (!callback)
+ value = b->buffer;
+
+ break;
+ }
+ }
- bool callback (b->callback != 0);
OCIBind* h (0);
sword r (OCIBindByPos (stmt_,
&h,
err,
i,
- callback ? 0 : b->buffer,
- // When parameter callbacks are in use, set the
- // allowable data length to the maximum
- // possible.
- //
+ value,
callback
- ? std::numeric_limits<sb4>::max ()
- : static_cast<sb4> (b->capacity),
+ ? std::numeric_limits<sb4>::max ()
+ : static_cast<sb4> (b->capacity),
param_sqlt_lookup[b->type],
- callback ? 0 : b->indicator,
- callback ? 0 : b->size,
+ b->indicator,
+ b->size,
0,
0,
0,
@@ -199,6 +301,8 @@ namespace odb
if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
translate_error (err, r);
+ // Set the character set form for national strings.
+ //
if (b->type == bind::nstring || b->type == bind::nclob)
{
ub1 form (SQLCS_NCHAR);
@@ -216,13 +320,6 @@ namespace odb
if (callback)
{
- details::buffer& lob_buffer (conn_.lob_buffer ());
-
- if (lob_buffer.capacity () == 0)
- lob_buffer.capacity (4096);
-
- b->buffer = &lob_buffer;
-
r = OCIBindDynamic (h, err, b, &param_callback_proxy, 0, 0);
if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
@@ -237,56 +334,146 @@ namespace odb
ODB_POTENTIALLY_UNUSED (p);
OCIError* err (conn_.error_handle ());
+ OCIEnv* env (conn_.database ().environment ());
for (size_t i (1); i <= c; ++i, ++b)
{
- OCIDefine* h (0);
+ void* value (0);
+ ub2* size (0);
- if (b->type == bind::blob ||
- b->type == bind::clob ||
- b->type == bind::nclob)
+ switch (b->type)
{
- // When binding a LOB result, the bind::buffer member is
- // reinterpreted as a pointer to an auto_descriptor<OCILobLocator>.
- // If the descriptor has not yet been allocated, it is allocated now.
- //
- auto_descriptor<OCILobLocator>* lob (
- reinterpret_cast<auto_descriptor<OCILobLocator>*> (b->buffer));
-
- if (lob->get () == 0)
+ case bind::timestamp:
+ {
+ datetime* dt (static_cast<datetime*> (b->buffer));
+
+ if (dt->descriptor.get () == 0)
+ {
+ void* d (0);
+ sword 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.environment = env;
+ dt->descriptor.error = err;
+ }
+
+ value = &dt->descriptor.get ();
+ break;
+ }
+ case bind::interval_ym:
{
- OCILobLocator* h (0);
+ interval_ym* iym (static_cast<interval_ym*> (b->buffer));
+
+ if (iym->descriptor.get () == 0)
+ {
+ void* d (0);
+ sword 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.environment = env;
+ iym->descriptor.error = err;
+ }
+
+ value = &iym->descriptor.get ();
+ break;
+ }
+ case bind::interval_ds:
+ {
+ interval_ds* ids (static_cast<interval_ds*> (b->buffer));
+
+ if (ids->descriptor.get () == 0)
+ {
+ void* d (0);
+ sword 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.environment = env;
+ ids->descriptor.error = err;
+ }
+
+ value = &ids->descriptor.get ();
+ break;
+ }
+ case bind::blob:
+ case bind::clob:
+ case bind::nclob:
+ {
+ auto_descriptor<OCILobLocator>* lob (
+ static_cast<auto_descriptor<OCILobLocator>*> (b->buffer));
+
+ if (lob->get () == 0)
+ {
+ void* d (0);
+ sword r (OCIDescriptorAlloc (env, &d, OCI_DTYPE_LOB, 0, 0));
- sword r (OCIDescriptorAlloc (conn_.database ().environment (),
- reinterpret_cast<void**> (&h),
- OCI_DTYPE_LOB,
- 0,
- 0));
+ if (r != OCI_SUCCESS)
+ throw invalid_oci_handle ();
- // OCIDescriptorAlloc will return OCI_SUCCESS on success, or
- // OCI_INVALID_HANDLE on an out-of-memory condition.
+ lob->reset (static_cast<OCILobLocator*> (d));
+ }
+
+ value = &lob->get ();
+ break;
+ }
+ default:
+ {
+#if OCI_MAJOR_VERSION < 11 || \
+ (OCI_MAJOR_VERSION == 11 && OCI_MINOR_VERSION < 2)
+ // Assert if a 64 bit integer buffer type is provided and the OCI
+ // version is unable to implicitly convert the NUMBER binary data
+ // to the relevant type.
//
- if (r != OCI_SUCCESS)
- throw invalid_oci_handle ();
+ assert ((b->type != bind::integer && b->type != bind::uinteger) ||
+ b->capacity <= 4);
+#endif
+ value = b->buffer;
+ size = b->size;
- lob->reset (h);
+ break;
}
+ }
- sword r (OCIDefineByPos (stmt_,
- &h,
- err,
- i,
- lob,
- sizeof (OCILobLocator*),
- result_sqlt_lookup[b->type],
- b->indicator,
- 0,
- 0,
- OCI_DEFAULT));
+ 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));
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (err, r);
+ if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
+ translate_error (err, r);
+ if (b->type == bind::blob ||
+ b->type == bind::clob ||
+ b->type == bind::nclob)
+ {
// The OCIDefine handle is stored in the size member of the bind in
// case the LOB parameter is rebound. If rebinding is necessary, the
// same OCIDefine handle is used.
@@ -316,47 +503,19 @@ namespace odb
}
#endif
}
- else
+ else if (b->type == bind::nstring)
{
-#if OCI_MAJOR_VERSION < 11 || \
- (OCI_MAJOR_VERSION == 11 && OCI_MINOR_VERSION < 2)
- // Assert if a 64 bit integer buffer type is provided and the OCI
- // version is unable to implicitly convert the NUMBER binary data
- // to the relevant type.
- //
- assert ((b->type != bind::integer && b->type != bind::uinteger) ||
- b->capacity <= 4);
-#endif
+ ub1 form (SQLCS_NCHAR);
- sword r (OCIDefineByPos (stmt_,
- &h,
- err,
- i,
- b->buffer,
- static_cast<sb4> (b->capacity),
- result_sqlt_lookup[b->type],
- b->indicator,
- b->size,
- 0,
- OCI_DEFAULT));
+ r = OCIAttrSet (h,
+ OCI_HTYPE_DEFINE,
+ &form,
+ 0,
+ OCI_ATTR_CHARSET_FORM,
+ err);
if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
translate_error (err, r);
-
- if (b->type == bind::nstring)
- {
- ub1 form (SQLCS_NCHAR);
-
- r = OCIAttrSet (h,
- OCI_HTYPE_DEFINE,
- &form,
- 0,
- OCI_ATTR_CHARSET_FORM,
- err);
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (err, r);
- }
}
}
}
@@ -366,49 +525,119 @@ namespace odb
{
ODB_POTENTIALLY_UNUSED (p);
- OCIError* err (conn_.error_handle ());
+ OCIEnv* env (conn_.database ().environment ());
for (size_t i (1); i <= c; ++i, ++b)
{
- if (!(b->type == bind::blob ||
- b->type == bind::clob ||
- b->type == bind::nclob))
- continue;
-
- // When binding a LOB result, the bind::buffer member is
- // reinterpreted as a pointer to an auto_descriptor<OCILobLocator>.
- // If the descriptor has been reset, it is re-allocated now.
- //
- auto_descriptor<OCILobLocator>* lob (
- reinterpret_cast<auto_descriptor<OCILobLocator>*> (b->buffer));
+ void* value (0);
- if (lob->get () == 0)
+ switch (b->type)
{
- OCILobLocator* h (0);
+ case bind::timestamp:
+ {
+ datetime* dt (static_cast<datetime*> (b->buffer));
- sword r (OCIDescriptorAlloc (conn_.database ().environment (),
- reinterpret_cast<void**> (&h),
- OCI_DTYPE_LOB,
- 0,
- 0));
+ if (dt->descriptor.get () == 0)
+ {
+ void* d (0);
+ sword r (OCIDescriptorAlloc (env,
+ &d,
+ OCI_DTYPE_TIMESTAMP,
+ 0,
+ 0));
- // OCIDescriptorAlloc will return OCI_SUCCESS on success, or
- // OCI_INVALID_HANDLE on an out-of-memory condition.
- //
- if (r != OCI_SUCCESS)
- throw invalid_oci_handle ();
+ if (r != OCI_SUCCESS)
+ throw invalid_oci_handle ();
- lob->reset (h);
+ dt->descriptor.reset (static_cast<OCIDateTime*> (d));
+ }
+
+ value = &dt->descriptor.get ();
+ break;
+ }
+ case bind::interval_ym:
+ {
+ interval_ym* iym (static_cast<interval_ym*> (b->buffer));
+
+ if (iym->descriptor.get () == 0)
+ {
+ void* d (0);
+ sword 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));
+ }
+
+ value = &iym->descriptor.get ();
+ break;
+ }
+ case bind::interval_ds:
+ {
+ interval_ds* ids (static_cast<interval_ds*> (b->buffer));
+
+ if (ids->descriptor.get () == 0)
+ {
+ void* d (0);
+ sword 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));
+ }
+
+ value = &ids->descriptor.get ();
+ break;
+ }
+ case bind::blob:
+ case bind::clob:
+ case bind::nclob:
+ {
+ auto_descriptor<OCILobLocator>* lob (
+ reinterpret_cast<auto_descriptor<OCILobLocator>*> (b->buffer));
+
+ if (lob->get () == 0)
+ {
+ void* d (0);
+ sword r (OCIDescriptorAlloc (env, &d, OCI_DTYPE_LOB, 0, 0));
+
+ if (r != OCI_SUCCESS)
+ throw invalid_oci_handle ();
+
+ lob->reset (static_cast <OCILobLocator*> (d));
+ }
+
+ value = &lob->get ();
+ break;
+ }
+ default:
+ {
+ continue;
+ }
}
+ // The bind::size member of bind instances associated with LOB and
+ // TIMESTAMP type is interpreted as the OCIDefine* returned by the
+ // initial call to OCIDefineByPos when binding for the first time.
+ //
OCIDefine* h (reinterpret_cast<OCIDefine*> (b->size));
sword r (OCIDefineByPos (stmt_,
&h,
- err,
+ conn_.error_handle (),
i,
- lob,
- sizeof (OCILobLocator*),
+ value,
+ static_cast<sb4> (b->capacity),
result_sqlt_lookup[b->type],
b->indicator,
0,
@@ -416,34 +645,7 @@ namespace odb
OCI_DEFAULT));
if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (err, r);
-
- // LOB prefetching is only supported in OCI version 11.1 and greater
- // and in Oracle server 11.1 and greater. If this code is called
- // against a pre 11.1 server, the call to OCIAttrSet will return an
- // error code.
- //
- // Note that even though we are re-binding the same handle, we still
- // have to reset this attribute. Failing to do so will result in the
- // mysterious ORA-03106 fatal two-task communication protocol error.
- //
-#if (OCI_MAJOR_VERSION == 11 && OCI_MINOR_VERSION >= 1) \
- || OCI_MAJOR_VERSION > 11
- if (p != 0)
- {
- ub4 n (static_cast<ub4> (p));
-
- r = OCIAttrSet (h,
- OCI_HTYPE_DEFINE,
- &n,
- 0,
- OCI_ATTR_LOBPREFETCH_SIZE,
- err);
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (err, r);
- }
-#endif
+ translate_error (conn_.error_handle (), r);
}
}
diff --git a/odb/oracle/traits.hxx b/odb/oracle/traits.hxx
index e8c3ec2..2ad3054 100644
--- a/odb/oracle/traits.hxx
+++ b/odb/oracle/traits.hxx
@@ -47,6 +47,8 @@ namespace odb
id_date,
id_timestamp,
+ id_interval_ym,
+ id_interval_ds,
id_string,
id_nstring,
@@ -181,11 +183,19 @@ namespace odb
template <typename T>
struct image_traits<T, id_timestamp>
{
- // Image is a buffer containing the native OCI TIMESTAMP representation.
- // This buffer has varying length, depending on the microsecond
- // precision of the TIMESTAMP value.
- //
- typedef char* image_type;
+ typedef datetime image_type;
+ };
+
+ template <typename T>
+ struct image_traits<T, id_interval_ym>
+ {
+ typedef interval_ym image_type;
+ };
+
+ template <typename T>
+ struct image_traits<T, id_interval_ds>
+ {
+ typedef interval_ds image_type;
};
template <typename T>
@@ -266,7 +276,7 @@ namespace odb
vtraits::set_image (i, is_null, wtraits::get_ref (v));
}
- // big_int, big_float, timestamp, string, nstring, raw.
+ // big_int, big_float, string, nstring, raw.
//
static void
set_value (W& v, const char* i, std::size_t n, bool is_null)
@@ -274,7 +284,7 @@ namespace odb
vtraits::set_value (wtraits::set_ref (v), i, n, is_null);
}
- // timestamp, string, nstring, raw.
+ // string, nstring, raw.
//
static void
set_image (char* i,
@@ -342,7 +352,7 @@ namespace odb
vtraits::set_image (i, is_null, wtraits::get_ref (v));
}
- // big_int, big_float, timestamp, string, nstring, raw.
+ // big_int, big_float, string, nstring, raw.
//
static void
set_value (W& v, const char* i, std::size_t n, bool is_null)
@@ -353,7 +363,7 @@ namespace odb
vtraits::set_value (wtraits::set_ref (v), i, n, is_null);
}
- // timestamp, string, nstring, raw.
+ // string, nstring, raw.
//
static void
set_image (char* i,