aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorConstantin Michael <constantin@codesynthesis.com>2011-09-28 09:57:42 +0200
committerConstantin Michael <constantin@codesynthesis.com>2011-09-29 08:56:13 +0200
commitec1683514402dfed20b8a08824e2aa1bb017d6e7 (patch)
treee37ad34c7fe5acd41ee8a9a9f6299d2cbc10c7be
parent9681c508fa9614da936314b9913a5d6cb0342c62 (diff)
Implement custom bind buffer type identifiers.
This allows for the association of a character set with a character data buffer, something that is impossible using only OCI external typecodes.
-rw-r--r--odb/oracle/oracle-fwd.hxx9
-rw-r--r--odb/oracle/oracle-types.hxx50
-rw-r--r--odb/oracle/statement.cxx75
3 files changed, 103 insertions, 31 deletions
diff --git a/odb/oracle/oracle-fwd.hxx b/odb/oracle/oracle-fwd.hxx
index a0cd2ed..bc400d1 100644
--- a/odb/oracle/oracle-fwd.hxx
+++ b/odb/oracle/oracle-fwd.hxx
@@ -24,15 +24,6 @@ typedef struct OCIStmt OCIStmt;
typedef struct OCIAuthInfo OCIAuthInfo;
typedef struct OCITrans OCITrans;
-// Define an external type identifier for the national character types.
-// These are used exclusively for identifying national character encoded
-// buffers while setting the character set form of an OCIBind or OCIDefine
-// handle. They are never passed to the OCI API.
-//
-extern ub2 SQLT_NCHAR;
-extern ub2 SQLT_NVARCHAR2;
-extern ub2 SQLT_NCLOB;
-
#include <odb/post.hxx>
#endif // ODB_ORACLE_ORACLE_FWD_HXX
diff --git a/odb/oracle/oracle-types.hxx b/odb/oracle/oracle-types.hxx
index c027e5d..d21b948 100644
--- a/odb/oracle/oracle-types.hxx
+++ b/odb/oracle/oracle-types.hxx
@@ -58,17 +58,45 @@ namespace odb
struct bind
{
- ub2 type; // The type stored by buffer. This must be an external
- // OCI type identifier of the form SQLT_XXX.
- void* buffer; // Data buffer pointer.
- ub2* size; // The number of bytes in buffer. When parameter
- // callbacks are in use, this is interpreted as a ub4*
- // indicating the current position. When result
- // callbacks are in use, this is interpreted as an
- // OCILobLocator*.
- ub4 capacity; // The maximum number of bytes that can be stored in
- // buffer.
- sb2* indicator; // Pointer to an OCI indicator variable.
+ // This enumeration identifies the possible buffer types that can be
+ // bound to a bind instance. In most cases, these map directly to
+ // SQLT_XXX codes, identifying an external OCI type. nstring and nclob
+ // however have no equivalent OCI typecode. These additional identifiers
+ // allow for a consistent interface across all types. Note that these
+ // values are mapped to their corresponding external OCI typecodes (if
+ // any) using their integer values, and should therefore not be
+ // rearranged or explicitly assigned without also adjusting the
+ // sqlt_lookup array in odb/oracle/statement.cxx.
+ //
+ enum buffer_type
+ {
+ integer, // Buffer is an integer type of size specified by size.
+ uinteger, // Buffer is an unsigned integer of size specified by
+ // size.
+ binary_float, // Buffer is a float.
+ 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.
+ string, // Buffer is a variable length char array.
+ nstring, // Buffer is a variable length char array.
+ blob, // Bind is a callback.
+ clob, // Bind is a callback.
+ nclob, // Bind is a callback.
+ last // Used as an end of list marker.
+ };
+
+ buffer_type type; // The type stored by buffer. This must be an external
+ // OCI type identifier of the form SQLT_XXX.
+ void* buffer; // Data buffer pointer.
+ ub2* size; // The number of bytes in buffer. When parameter
+ // callbacks are in use, this is interpreted as a ub4*
+ // indicating the current position. When result
+ // callbacks are in use, this is interpreted as an
+ // OCILobLocator*.
+ ub4 capacity; // The maximum number of bytes that can be stored in
+ // buffer.
+ sb2* indicator; // Pointer to an OCI indicator variable.
lob_callback callback;
diff --git a/odb/oracle/statement.cxx b/odb/oracle/statement.cxx
index 4e35fe5..f923da6 100644
--- a/odb/oracle/statement.cxx
+++ b/odb/oracle/statement.cxx
@@ -23,6 +23,25 @@ namespace odb
{
namespace oracle
{
+ // Mapping of bind::buffer_type values to there equivalent external
+ // OCI typecode identifiers.
+ //
+ static ub4 sqlt_lookup[bind::last] =
+ {
+ SQLT_INT,
+ SQLT_UIN,
+ SQLT_BFLOAT,
+ SQLT_BDOUBLE,
+ SQLT_VNU,
+ SQLT_DAT,
+ SQLT_TIMESTAMP,
+ SQLT_CHR,
+ SQLT_CHR,
+ SQLT_BLOB,
+ SQLT_CLOB,
+ SQLT_CLOB
+ };
+
static sb4
param_callback_proxy (void* context,
OCIBind*,
@@ -126,8 +145,7 @@ namespace odb
// version is unable to implicitly convert the NUMBER binary data
// to the relevant type.
//
- assert ((b->type != SQLT_INT && b->type != SQLT_UIN) ||
- b->capacity <= 4);
+ assert (b->type != bind::integer || b->capacity <= 4);
#endif
OCIBind* h (0);
@@ -137,7 +155,7 @@ namespace odb
o,
b->buffer,
static_cast<sb4> (b->capacity),
- b->type,
+ sqlt_lookup[b->type],
b->indicator,
b->size,
0,
@@ -149,6 +167,21 @@ namespace odb
if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
translate_error (err, r);
+ if (b->type == bind::nstring || b->type == bind::nclob)
+ {
+ ub1 form (SQLCS_NCHAR);
+
+ r = OCIAttrSet (h,
+ OCI_HTYPE_BIND,
+ &form,
+ 0,
+ OCI_ATTR_CHARSET_FORM,
+ err);
+
+ if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
+ translate_error (err, r);
+ }
+
if (b->callback.param != 0)
{
r = OCIBindDynamic (h, err, b, &param_callback_proxy, 0, 0);
@@ -168,16 +201,19 @@ namespace odb
for (size_t i (1); i <= c; ++i, ++b)
{
- if (b->type == SQLT_BLOB || b->type == SQLT_CLOB)
+ OCIDefine* h (0);
+
+ if (b->type == bind::blob ||
+ b->type == bind::clob ||
+ b->type == bind::nclob)
{
- OCIDefine* h (0);
sword r (OCIDefineByPos (stmt_,
&h,
err,
i,
reinterpret_cast<OCILobLocator*> (b->size),
sizeof (OCILobLocator*),
- b->type,
+ sqlt_lookup[b->type],
b->indicator,
0,
0,
@@ -215,18 +251,17 @@ namespace odb
// version is unable to implicitly convert the NUMBER binary data
// to the relevant type.
//
- assert ((b->type != SQLT_INT && b->type != SQLT_UIN) ||
+ assert ((b->type != bind::integer || b->type != bind::uinteger) &&
b->capacity <= 4);
#endif
- OCIDefine* h (0);
sword r (OCIDefineByPos (stmt_,
&h,
err,
i,
b->buffer,
static_cast<sb4> (b->capacity),
- b->type,
+ sqlt_lookup[b->type],
b->indicator,
b->size,
0,
@@ -234,6 +269,21 @@ namespace odb
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_BIND,
+ &form,
+ 0,
+ OCI_ATTR_CHARSET_FORM,
+ err);
+
+ if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
+ translate_error (err, r);
+ }
}
}
}
@@ -248,7 +298,9 @@ namespace odb
// Only stream if the bind specifies a LOB type, and the LOB value is
// not NULL, and a result callback has been provided.
//
- if ((b->type == SQLT_BLOB || b->type == SQLT_CLOB) &&
+ if ((b->type == bind::blob ||
+ b->type == bind::clob ||
+ b->type == bind::nclob) &&
*b->indicator != -1 &&
b->callback.result != 0)
{
@@ -266,6 +318,7 @@ namespace odb
// return OCI_SUCCESS.
//
ub8 read (0);
+ ub1 cs_form (b->type == bind::nclob ? SQLCS_NCHAR : SQLCS_IMPLICIT);
sword r;
do
@@ -282,7 +335,7 @@ namespace odb
0,
0,
0,
- SQLCS_IMPLICIT);
+ cs_form);
if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
translate_error (err, r);