aboutsummaryrefslogtreecommitdiff
path: root/odb/oracle
diff options
context:
space:
mode:
authorConstantin Michael <constantin@codesynthesis.com>2011-10-28 14:19:20 +0200
committerConstantin Michael <constantin@codesynthesis.com>2011-11-01 13:19:26 +0200
commitb7a9c4a4efecff45f35652e50d0ae56cea4ade42 (patch)
treea8cea32d2c349d948ef9aa8543dd1b35e7503942 /odb/oracle
parent1cc4eb4d11c08f986408c9b671840b6e077b42ff (diff)
Implement change callbacks for object_result and view_result
Diffstat (limited to 'odb/oracle')
-rw-r--r--odb/oracle/auto-descriptor.hxx2
-rw-r--r--odb/oracle/object-result.hxx12
-rw-r--r--odb/oracle/object-result.txx78
-rw-r--r--odb/oracle/object-statements.txx4
-rw-r--r--odb/oracle/oracle-types.hxx4
-rw-r--r--odb/oracle/statement.cxx91
-rw-r--r--odb/oracle/statement.hxx13
-rw-r--r--odb/oracle/view-result.hxx6
-rw-r--r--odb/oracle/view-result.txx39
-rw-r--r--odb/oracle/view-statements.txx2
10 files changed, 238 insertions, 13 deletions
diff --git a/odb/oracle/auto-descriptor.hxx b/odb/oracle/auto-descriptor.hxx
index cd537ef..f55925d 100644
--- a/odb/oracle/auto-descriptor.hxx
+++ b/odb/oracle/auto-descriptor.hxx
@@ -85,7 +85,7 @@ namespace odb
d_ = d;
}
- protected:
+ private:
auto_descriptor (const auto_descriptor&);
auto_descriptor& operator= (const auto_descriptor&);
diff --git a/odb/oracle/object-result.hxx b/odb/oracle/object-result.hxx
index 5e23978..8751948 100644
--- a/odb/oracle/object-result.hxx
+++ b/odb/oracle/object-result.hxx
@@ -59,8 +59,14 @@ namespace odb
using base_type::current;
private:
+ static void
+ change_callback (void* context);
+
+ private:
details::shared_ptr<select_statement> statement_;
object_statements<object_type>& statements_;
+ bool use_copy_;
+ typename object_traits::image_type* image_copy_;
};
template <typename T>
@@ -97,8 +103,14 @@ namespace odb
using base_type::current;
private:
+ static void
+ change_callback (void* context);
+
+ private:
details::shared_ptr<select_statement> statement_;
object_statements_no_id<object_type>& statements_;
+ bool use_copy_;
+ typename object_traits::image_type* image_copy_;
};
}
}
diff --git a/odb/oracle/object-result.txx b/odb/oracle/object-result.txx
index e3eeca4..66077f3 100644
--- a/odb/oracle/object-result.txx
+++ b/odb/oracle/object-result.txx
@@ -20,6 +20,8 @@ namespace odb
object_result_impl<T>::
~object_result_impl ()
{
+ statements_.image ().change_callback_.callback = 0;
+ delete image_copy_;
}
template <typename T>
@@ -29,7 +31,9 @@ namespace odb
object_statements<object_type>& statements)
: base_type (statements.connection ().database ()),
statement_ (statement),
- statements_ (statements)
+ statements_ (statements),
+ use_copy_ (false),
+ image_copy_ (0)
{
}
@@ -45,7 +49,9 @@ namespace odb
odb::database& db (this->database ());
object_traits::callback (db, obj, callback_event::pre_load);
- typename object_traits::image_type& i (statements_.image ());
+ typename object_traits::image_type& i (
+ use_copy_ ? *image_copy_ : statements_.image ());
+
object_traits::init (obj, i, db);
statement_->stream_result ();
@@ -85,6 +91,9 @@ namespace odb
typename object_traits::image_type& im (statements_.image ());
+ im.change_callback_.callback = 0;
+ use_copy_ = false;
+
if (im.version != statements_.select_image_version ())
{
binding& b (statements_.select_image_binding ());
@@ -95,6 +104,11 @@ namespace odb
if (statement_->fetch () == select_statement::no_data)
this->end_ = true;
+ else
+ {
+ im.change_callback_.callback = &change_callback;
+ im.change_callback_.context = this;
+ }
}
template <typename T>
@@ -110,6 +124,24 @@ namespace odb
throw result_not_cached ();
}
+ template <typename T>
+ void object_result_impl<T>::
+ change_callback (void* c)
+ {
+ object_result_impl<T>* r (static_cast<object_result_impl<T>*> (c));
+ object_statements<object_type>& stmts (r->statements_);
+
+ if (r->image_copy_ == 0)
+ r->image_copy_ = new
+ typename object_traits::image_type (stmts.image ());
+ else
+ *r->image_copy_ = stmts.image ();
+
+ stmts.select_image_binding ().version++;
+ stmts.image ().change_callback_.callback = 0;
+ r->use_copy_ = true;
+ }
+
//
// object_result_impl_no_id
//
@@ -118,6 +150,8 @@ namespace odb
object_result_impl_no_id<T>::
~object_result_impl_no_id ()
{
+ statements_.image ().change_callback_.callback = 0;
+ delete image_copy_;
}
template <typename T>
@@ -127,7 +161,9 @@ namespace odb
object_statements_no_id<object_type>& statements)
: base_type (statements.connection ().database ()),
statement_ (statement),
- statements_ (statements)
+ statements_ (statements),
+ use_copy_ (false),
+ image_copy_ (0)
{
}
@@ -138,8 +174,14 @@ namespace odb
odb::database& db (this->database ());
object_traits::callback (db, obj, callback_event::pre_load);
- object_traits::init (obj, statements_.image (), db);
+
+ if (use_copy_)
+ object_traits::init (obj, *image_copy_, db);
+ else
+ object_traits::init (obj, statements_.image (), db);
+
statement_->stream_result ();
+
object_traits::callback (db, obj, callback_event::post_load);
}
@@ -151,6 +193,9 @@ namespace odb
typename object_traits::image_type& im (statements_.image ());
+ im.change_callback_.callback = 0;
+ use_copy_ = false;
+
if (im.version != statements_.select_image_version ())
{
binding& b (statements_.select_image_binding ());
@@ -161,6 +206,11 @@ namespace odb
if (statement_->fetch () == select_statement::no_data)
this->end_ = true;
+ else
+ {
+ im.change_callback_.callback = &change_callback;
+ im.change_callback_.context = this;
+ }
}
template <typename T>
@@ -175,5 +225,25 @@ namespace odb
{
throw result_not_cached ();
}
+
+ template <typename T>
+ void object_result_impl_no_id<T>::
+ change_callback (void* c)
+ {
+ object_result_impl_no_id<T>* r (
+ static_cast<object_result_impl_no_id<T>*> (c));
+
+ object_statements_no_id<object_type>& stmts (r->statements_);
+
+ if (r->image_copy_ == 0)
+ r->image_copy_ = new
+ typename object_traits::image_type (stmts.image ());
+ else
+ *r->image_copy_ = stmts.image ();
+
+ stmts.select_image_binding ().version++;
+ stmts.image ().change_callback_.callback = 0;
+ r->use_copy_ = true;
+ }
}
}
diff --git a/odb/oracle/object-statements.txx b/odb/oracle/object-statements.txx
index 948251f..212c03c 100644
--- a/odb/oracle/object-statements.txx
+++ b/odb/oracle/object-statements.txx
@@ -45,7 +45,7 @@ namespace odb
id_image_.version = 0;
id_image_version_ = 0;
- select_image_binding_.change_callback = &image_.change_callback;
+ select_image_binding_.change_callback = image_.change_callback ();
std::memset (insert_image_bind_, 0, sizeof (insert_image_bind_));
std::memset (update_image_bind_, 0, sizeof (update_image_bind_));
@@ -139,7 +139,7 @@ namespace odb
select_image_version_ = 0;
insert_image_version_ = 0;
- select_image_binding_.change_callback = &image_.change_callback;
+ select_image_binding_.change_callback = image_.change_callback ();
std::memset (insert_image_bind_, 0, sizeof (insert_image_bind_));
std::memset (select_image_bind_, 0, sizeof (select_image_bind_));
diff --git a/odb/oracle/oracle-types.hxx b/odb/oracle/oracle-types.hxx
index 1e94894..5587861 100644
--- a/odb/oracle/oracle-types.hxx
+++ b/odb/oracle/oracle-types.hxx
@@ -141,11 +141,9 @@ namespace odb
}
lob_auto_descriptor (lob_auto_descriptor& x)
- : auto_descriptor<OCILobLocator> (0)
+ : auto_descriptor<OCILobLocator> (x.d_)
{
- OCILobLocator* l (x.d_);
x.d_ = 0;
- reset (l);
}
lob_auto_descriptor&
diff --git a/odb/oracle/statement.cxx b/odb/oracle/statement.cxx
index ebddf0c..bddd539 100644
--- a/odb/oracle/statement.cxx
+++ b/odb/oracle/statement.cxx
@@ -355,6 +355,85 @@ namespace odb
}
void statement::
+ rebind_result (bind* b, size_t c, size_t p)
+ {
+ ODB_POTENTIALLY_UNUSED (p);
+
+ OCIError* err (conn_.error_handle ());
+
+ 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));
+
+ if (lob->get () == 0)
+ {
+ OCILobLocator* h (0);
+
+ sword r (OCIDescriptorAlloc (conn_.database ().environment (),
+ reinterpret_cast<void**> (&h),
+ OCI_DTYPE_LOB,
+ 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 ();
+
+ lob->reset (h);
+ }
+
+ OCIDefine* h(0);
+ sword r (OCIDefineByPos (stmt_,
+ &h,
+ err,
+ i,
+ lob,
+ sizeof (OCILobLocator*),
+ result_sqlt_lookup[b->type],
+ b->indicator,
+ 0,
+ 0,
+ 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.
+ //
+#if (OCI_MAJOR_VERSION == 11 && OCI_MINOR_VERSION >= 1) \
+ || OCI_MAJOR_VERSION > 11
+ if (p != 0)
+ {
+ r = OCIAttrSet (h,
+ OCI_HTYPE_DEFINE,
+ &p,
+ 0,
+ OCI_ATTR_LOBPREFETCH_SIZE,
+ err);
+
+ if (r == OCI_ERROR || r == OCI_INVALID_HANDLE)
+ translate_error (err, r);
+ }
+#endif
+ }
+ }
+
+ void statement::
stream_result (bind* b, size_t c)
{
OCIError* err (conn_.error_handle());
@@ -456,10 +535,13 @@ namespace odb
size_t lob_prefetch_size)
: statement (conn, s),
data_ (data),
+ data_version_ (0),
+ lob_prefetch_size_ (lob_prefetch_size),
done_ (true)
{
bind_param (cond.bind, cond.count, 0);
bind_result (data.bind, data.count, lob_prefetch_size);
+ data_version_ = data_.version;
}
select_statement::
@@ -469,9 +551,12 @@ namespace odb
size_t lob_prefetch_size)
: statement (conn, s),
data_ (data),
+ data_version_ (0),
+ lob_prefetch_size_ (lob_prefetch_size),
done_ (true)
{
bind_result (data.bind, data.count, lob_prefetch_size);
+ data_version_ = data_.version;
}
void select_statement::
@@ -526,6 +611,12 @@ namespace odb
if (cc != 0 && cc->callback != 0)
(cc->callback) (cc->context);
+ if (data_version_ != data_.version)
+ {
+ rebind_result (data_.bind, data_.count, lob_prefetch_size_);
+ data_version_ = data_.version;
+ }
+
sword r (OCIStmtFetch2 (stmt_,
conn_.error_handle (),
1,
diff --git a/odb/oracle/statement.hxx b/odb/oracle/statement.hxx
index d942e82..a883d6c 100644
--- a/odb/oracle/statement.hxx
+++ b/odb/oracle/statement.hxx
@@ -52,6 +52,17 @@ namespace odb
std::size_t count,
std::size_t lob_prefetch_size = 0);
+ // Rebind LOB input parameters. If a query has made a private copy of
+ // the shared image, any LOB handles that were previously owned by the
+ // shared image are now owned by the private image of the query. These
+ // LOB handles need to be reallocated and redefined so that any unfetched
+ // results may be fetched.
+ //
+ void
+ rebind_result (bind*,
+ std::size_t count,
+ std::size_t lob_prefetch_size = 0);
+
// Stream the result LOBs, calling user callbacks where necessary.
//
void
@@ -106,6 +117,8 @@ namespace odb
private:
binding& data_;
+ std::size_t data_version_;
+ const std::size_t lob_prefetch_size_;
bool done_;
};
diff --git a/odb/oracle/view-result.hxx b/odb/oracle/view-result.hxx
index ec70194..063680f 100644
--- a/odb/oracle/view-result.hxx
+++ b/odb/oracle/view-result.hxx
@@ -55,8 +55,14 @@ namespace odb
using base_type::current;
private:
+ static void
+ change_callback (void* context);
+
+ private:
details::shared_ptr<select_statement> statement_;
view_statements<view_type>& statements_;
+ bool use_copy_;
+ typename view_traits::image_type* image_copy_;
};
}
}
diff --git a/odb/oracle/view-result.txx b/odb/oracle/view-result.txx
index 8f2262b..361e63e 100644
--- a/odb/oracle/view-result.txx
+++ b/odb/oracle/view-result.txx
@@ -16,6 +16,8 @@ namespace odb
view_result_impl<T>::
~view_result_impl ()
{
+ statements_.image ().change_callback_.callback = 0;
+ delete image_copy_;
}
template <typename T>
@@ -25,7 +27,9 @@ namespace odb
view_statements<view_type>& statements)
: base_type (statements.connection ().database ()),
statement_ (statement),
- statements_ (statements)
+ statements_ (statements),
+ use_copy_ (false),
+ image_copy_ (0)
{
}
@@ -36,7 +40,12 @@ namespace odb
odb::database& db (this->database ());
view_traits::callback (db, view, callback_event::pre_load);
- view_traits::init (view, statements_.image (), db);
+
+ if (use_copy_)
+ view_traits::init (view, *image_copy_, db);
+ else
+ view_traits::init (view, statements_.image (), db);
+
statement_->stream_result ();
view_traits::callback (db, view, callback_event::post_load);
}
@@ -49,6 +58,9 @@ namespace odb
typename view_traits::image_type& im (statements_.image ());
+ im.change_callback_.callback = 0;
+ use_copy_ = false;
+
if (im.version != statements_.image_version ())
{
binding& b (statements_.image_binding ());
@@ -59,6 +71,11 @@ namespace odb
if (statement_->fetch () == select_statement::no_data)
this->end_ = true;
+ else
+ {
+ im.change_callback_.callback = &change_callback;
+ im.change_callback_.context = this;
+ }
}
template <typename T>
@@ -73,5 +90,23 @@ namespace odb
{
throw result_not_cached ();
}
+
+ template <typename T>
+ void view_result_impl<T>::
+ change_callback (void* c)
+ {
+ view_result_impl<T>* r (static_cast<view_result_impl<T>*> (c));
+ view_statements<view_type>& stmts (r->statements_);
+
+ if (r->image_copy_ == 0)
+ r->image_copy_ = new
+ typename view_traits::image_type (stmts.image ());
+ else
+ *r->image_copy_ = stmts.image ();
+
+ stmts.image_binding ().version++;
+ stmts.image ().change_callback_.callback = 0;
+ r->use_copy_ = true;
+ }
}
}
diff --git a/odb/oracle/view-statements.txx b/odb/oracle/view-statements.txx
index eefe503..9bb601b 100644
--- a/odb/oracle/view-statements.txx
+++ b/odb/oracle/view-statements.txx
@@ -25,7 +25,7 @@ namespace odb
image_.version = 0;
image_version_ = 0;
- image_binding_.change_callback = &image_.change_callback;
+ image_binding_.change_callback = image_.change_callback ();
std::memset (image_bind_, 0, sizeof (image_bind_));
std::memset (image_indicator_, 0, sizeof (image_indicator_));