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.cxx233
1 files changed, 111 insertions, 122 deletions
diff --git a/odb/oracle/statement.cxx b/odb/oracle/statement.cxx
index 32b015a..70859a4 100644
--- a/odb/oracle/statement.cxx
+++ b/odb/oracle/statement.cxx
@@ -13,8 +13,9 @@
#include <odb/oracle/database.hxx>
#include <odb/oracle/statement.hxx>
#include <odb/oracle/connection.hxx>
-#include <odb/oracle/error.hxx>
#include <odb/oracle/auto-descriptor.hxx>
+#include <odb/oracle/error.hxx>
+#include <odb/oracle/exceptions.hxx>
using namespace std;
@@ -28,52 +29,48 @@ namespace odb
ub4, // iteration
ub4, // index
void** buffer,
- ub4* len,
+ ub4* size,
ub1* piece,
void** indicator)
{
bind& b (*static_cast<bind*> (context));
- // Only callback to user if the parameter is not NULL.
+ // Only call callback if the parameter is not NULL.
//
if (*b.indicator != -1)
{
- bind::piece p;
-
+ chunk_position pos;
if (!(*b.callback.param) (&b.callback_context,
- buffer,
- len,
reinterpret_cast<ub4*> (b.size),
- &p,
+ buffer,
+ size,
+ &pos,
b.buffer,
b.capacity))
return OCI_ERROR;
- switch (p)
+ switch (pos)
{
- case bind::whole:
+ case one_chunk:
{
*piece = OCI_ONE_PIECE;
break;
}
- case bind::first:
+ case first_chunk:
{
*piece = OCI_FIRST_PIECE;
break;
}
- case bind::next:
+ case next_chunk:
{
*piece = OCI_NEXT_PIECE;
break;
}
- case bind::last:
+ case last_chunk:
{
*piece = OCI_LAST_PIECE;
break;
}
- default:
- assert (0);
- return OCI_ERROR;
}
}
else
@@ -117,17 +114,13 @@ namespace odb
OCIError* err (conn_.error_handle ());
// The parameter position in OCIBindByPos is specified as a 1-based
- // index. Convert 'o' to a 1-based offset.
+ // index. Convert o to a 1-based offset.
//
++o;
for (size_t e (o + c); o < e; ++c, ++b)
{
- bool callback ((b->type == SQLT_BLOB || b->type == SQLT_CLOB) &&
- b->callback.param != 0);
-
OCIBind* h (0);
-
sword r (OCIBindByPos (stmt_,
&h,
err,
@@ -140,12 +133,13 @@ namespace odb
0,
0,
0,
- callback ? OCI_DATA_AT_EXEC : OCI_DEFAULT));
+ b->callback.param != 0 ?
+ OCI_DATA_AT_EXEC : OCI_DEFAULT));
if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
translate_error (err, r);
- if (callback)
+ if (b->callback.param != 0)
{
r = OCIBindDynamic (h, err, b, &param_callback_proxy, 0, 0);
@@ -162,9 +156,9 @@ namespace odb
OCIError* err (conn_.error_handle ());
- // The parameter position in OCIDefineByPos is specified as a 1-based
- // index.
- //
+ result_binds_ = b;
+ count_ = c;
+
for (size_t i (1); i <= c; ++i, ++b)
{
if (b->type == SQLT_BLOB || b->type == SQLT_CLOB)
@@ -185,10 +179,10 @@ namespace odb
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.
+ // 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.
//
#if (OCI_MAJOR_VERSION == 11 && OCI_MINOR_VERSION >= 1) \
|| OCI_MAJOR_VERSION > 11
@@ -204,7 +198,7 @@ namespace odb
if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
translate_error (err, r);
- bool b (true);
+ boolean b (true);
r = OCIAttrSet (h,
OCI_HTYPE_DEFINE,
&b,
@@ -238,6 +232,81 @@ namespace odb
}
}
+ void statement::
+ stream_result_lobs ()
+ {
+ OCIError* err (conn_.error_handle());
+
+ for (size_t i (0); i < count_; ++i)
+ {
+ bind& b (result_binds_[i]);
+
+ // 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) &&
+ *b.indicator != -1 &&
+ b.callback.result != 0)
+ {
+ // If b.capacity is 0, we will be stuck in an infinite loop.
+ //
+ assert (b.capacity != 0);
+
+ OCILobLocator* locator (reinterpret_cast<OCILobLocator*> (b.size));
+
+ ub8 size (0);
+ sword r (OCILobGetLength2(conn_.handle (),
+ err,
+ locator,
+ &size));
+
+ if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
+ translate_error (err, r);
+
+ ub1 piece (OCI_FIRST_PIECE);
+ ub8 read (size);
+
+ do
+ {
+ r = OCILobRead2 (conn_.handle (),
+ err,
+ locator,
+ &read,
+ 0,
+ 1,
+ b.buffer,
+ b.capacity,
+ piece,
+ 0,
+ 0,
+ 0,
+ SQLCS_IMPLICIT);
+
+ if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
+ translate_error (err, r);
+
+ chunk_position cp;
+
+ if (piece == OCI_FIRST_PIECE)
+ cp = read == size ? one_chunk : first_chunk;
+ else if (r == OCI_NEED_DATA)
+ cp = next_chunk;
+ else
+ cp = last_chunk;
+
+ if (!(*b.callback.result) (b.callback_context,
+ b.buffer,
+ static_cast<ub4> (read),
+ cp))
+ throw database_exception (24343, "user defined callback error");
+
+ piece = OCI_NEXT_PIECE;
+
+ } while (r == OCI_NEED_DATA);
+ }
+ }
+ }
+
statement::
~statement ()
{
@@ -257,13 +326,12 @@ namespace odb
const string& s,
binding& cond,
binding& data,
- std::size_t lob_prefetch_len)
+ std::size_t lob_prefetch_size)
: statement (conn, s),
- data_ (data),
done_ (false)
{
bind_param (cond.bind, cond.count, 0);
- bind_result (data.bind, data.count, lob_prefetch_len);
+ bind_result (data.bind, data.count, lob_prefetch_size);
}
void select_statement::
@@ -272,10 +340,10 @@ namespace odb
if (!done_)
free_result ();
- // @@ Retrieve a single row into the already bound output buffers
- // as an optimization? This will avoid multiple server round-trips
- // in the case of a single object load. Keep in mind the implications
- // on LOB prefetch.
+ // @@ Retrieve a single row into the already bound output buffers as an
+ // optimization? This will avoid multiple server round-trips in the case
+ // of a single object load. Keep the implications on LOB prefetch in
+ // mind.
//
sword r (OCIStmtExecute (conn_.handle (),
stmt_,
@@ -330,85 +398,6 @@ namespace odb
}
}
- void select_statement::
- stream_result_lobs ()
- {
- OCIError* err (conn_.error_handle());
-
- for (size_t i (0); i < data_.count; ++i)
- {
- // Only stream if the bind specifies a LOB type, and the LOB
- // value is not NULL, and a result callback has been provided.
- //
- if ((data_.bind[i].type == SQLT_BLOB ||
- data_.bind[i].type == SQLT_CLOB) &&
- *data_.bind[i].indicator != -1 &&
- data_.bind[i].callback.result != 0)
- {
- // @@ If data_.bind[i].capacity is 0, we will be stuck in an
- // infinite loop.
- //
- assert (data_.bind[i].capacity != 0);
-
- OCILobLocator* locator (
- reinterpret_cast<OCILobLocator*> (data_.bind[i].size));
-
- ub8 length (0);
- sword r (OCILobGetLength2(conn_.handle (),
- err,
- locator,
- &length));
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (err, r);
-
- for (ub8 total (0), read (0); total < length; total += read)
- {
- read = length - total;
- read = read > data_.bind[i].capacity ?
- data_.bind[i].capacity : read;
-
- // The call to OCILobRead2 does not need to know when the last
- // piece is being requested.
- //
- ub1 oci_piece (total == 0 ? OCI_FIRST_PIECE : OCI_NEXT_PIECE);
-
- r = OCILobRead2 (conn_.handle (),
- err,
- locator,
- &read,
- 0,
- 1, // Starting offset. The first position is 1.
- // This parameter is only used by OCI on the
- // first call when polling.
- data_.bind[i].buffer,
- data_.bind[i].capacity,
- oci_piece,
- 0,
- 0,
- 0,
- SQLCS_IMPLICIT);
-
- if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
- translate_error (err, r);
-
- bind::piece user_piece;
- if (oci_piece == OCI_FIRST_PIECE)
- user_piece = read == length ? bind::whole : bind::first;
- else
- user_piece = total + read < length ? bind::next : bind::last;
-
- if (!(*data_.bind[i].callback.result) (
- data_.bind[i].callback_context,
- data_.bind[i].buffer,
- read,
- user_piece))
- break;
- }
- }
- }
- }
-
//
// insert_statement
//
@@ -419,7 +408,7 @@ namespace odb
ub4, // iter
ub4, // index
void** buffer,
- ub4* len,
+ ub4* size,
ub1* piece,
void** indicator)
{
@@ -428,7 +417,7 @@ namespace odb
bind& b (*static_cast<bind*> (context));
*buffer = 0;
- *len = 0;
+ *size = 0;
*piece = OCI_ONE_PIECE;
b.indicator = -1;
*indicator = &b.indicator;
@@ -442,7 +431,7 @@ namespace odb
ub4, // iter
ub4, // index
void** buffer,
- ub4** len,
+ ub4** size,
ub1*, // piece
void** indicator,
ub2** rcode)
@@ -454,10 +443,10 @@ namespace odb
#if (OCI_MAJOR_VERSION == 11 && OCI_MINOR_VERSION >=2) \
|| OCI_MAJOR_VERSION > 11
*buffer = &b.id.value64;
- **len = sizeof (unsigned long long);
+ **size = sizeof (unsigned long long);
#else
*buffer = &b.id.value32;
- **len = sizeof (unsigned int);
+ **size = sizeof (unsigned int);
#endif
*indicator = &b.indicator;