aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorConstantin Michael <constantin@codesynthesis.com>2011-09-19 10:43:42 +0200
committerConstantin Michael <constantin@codesynthesis.com>2011-09-19 10:43:42 +0200
commitf1de6d3f15de3239f5e95587e3486ab6e86e3e78 (patch)
tree6a5436e25abf18534c0946b3d877f63531781dcd
parent946c283a971f09a4d1f72066d17a684f62f51d88 (diff)
Refactor stream_lobs so that base statement class does not maintain state
-rw-r--r--odb/oracle/statement.cxx51
-rw-r--r--odb/oracle/statement.hxx12
2 files changed, 37 insertions, 26 deletions
diff --git a/odb/oracle/statement.cxx b/odb/oracle/statement.cxx
index 5a31a13..c2891a6 100644
--- a/odb/oracle/statement.cxx
+++ b/odb/oracle/statement.cxx
@@ -35,7 +35,7 @@ namespace odb
{
bind& b (*static_cast<bind*> (context));
- // Only call callback if the parameter is not NULL.
+ // Only call the callback if the parameter is not NULL.
//
if (*b.indicator != -1)
{
@@ -156,9 +156,6 @@ namespace odb
OCIError* err (conn_.error_handle ());
- result_binds_ = b;
- count_ = c;
-
for (size_t i (1); i <= c; ++i, ++b)
{
if (b->type == SQLT_BLOB || b->type == SQLT_CLOB)
@@ -233,27 +230,33 @@ namespace odb
}
void statement::
- stream_result_lobs ()
+ stream_result (bind* b, size_t c)
{
OCIError* err (conn_.error_handle());
- for (size_t i (0); i < count_; ++i)
+ for (size_t i (0); i < c; ++i, ++b)
{
- 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->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.
+ // If b->capacity is 0, we will be stuck in an infinite loop.
//
- assert (b.capacity != 0);
+ assert (b->capacity != 0);
- OCILobLocator* locator (reinterpret_cast<OCILobLocator*> (b.size));
+ OCILobLocator* locator (reinterpret_cast<OCILobLocator*> (b->size));
+ // We have to get the length of the LOB due to a limitation of the
+ // polling interface. OCI requires that the maximum number of bytes
+ // to read be specified on the first call to OCILobRead2. The
+ // maximum size of a LOB is determined by the server CHUNK size,
+ // which requires an additional round-trip to obtain. Getting the
+ // LOB length is simpler and no less efficient. A possible
+ // alternative is to use callbacks as opposed to polling.
+ //
ub8 size (0);
sword r (OCILobGetLength2(conn_.handle (),
err,
@@ -274,8 +277,8 @@ namespace odb
&read,
0,
1,
- b.buffer,
- b.capacity,
+ b->buffer,
+ b->capacity,
piece,
0,
0,
@@ -294,10 +297,13 @@ namespace odb
else
cp = last_chunk;
- if (!(*b.callback.result) (b.callback_context,
- b.buffer,
- static_cast<ub4> (read),
- cp))
+ // OCI generates and ORA-24343 error when an error code is
+ // returned from a user callback. We simulate this.
+ //
+ 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;
@@ -328,6 +334,7 @@ namespace odb
binding& data,
size_t lob_prefetch_size)
: statement (conn, s),
+ data_ (data),
done_ (false)
{
bind_param (cond.bind, cond.count, 0);
@@ -340,6 +347,7 @@ namespace odb
binding& data,
size_t lob_prefetch_size)
: statement (conn, s),
+ data_ (data),
done_ (false)
{
bind_result (data.bind, data.count, lob_prefetch_size);
@@ -353,8 +361,7 @@ namespace odb
// @@ 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.
+ // of a single object load.
//
sword r (OCIStmtExecute (conn_.handle (),
stmt_,
diff --git a/odb/oracle/statement.hxx b/odb/oracle/statement.hxx
index 8d0b491..d942e82 100644
--- a/odb/oracle/statement.hxx
+++ b/odb/oracle/statement.hxx
@@ -55,14 +55,11 @@ namespace odb
// Stream the result LOBs, calling user callbacks where necessary.
//
void
- stream_result_lobs ();
+ stream_result (bind*, std::size_t count);
protected:
connection& conn_;
auto_handle<OCIStmt> stmt_;
-
- bind* result_binds_;
- std::size_t count_;
};
class LIBODB_ORACLE_EXPORT select_statement: public statement
@@ -95,6 +92,12 @@ namespace odb
fetch ();
void
+ stream_result ()
+ {
+ statement::stream_result (data_.bind, data_.count);
+ }
+
+ void
free_result ();
private:
@@ -102,6 +105,7 @@ namespace odb
select_statement& operator= (const select_statement&);
private:
+ binding& data_;
bool done_;
};