aboutsummaryrefslogtreecommitdiff
path: root/odb/mysql/result.txx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2010-11-26 15:48:28 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2010-11-26 15:48:28 +0200
commit61fc247f34255796f5535b52626074b4f92b6bb4 (patch)
tree347d00cedcee85f7d75a5976a210ab07ef33c7be /odb/mysql/result.txx
parentba8430c002627705d559b5dd9d78ae7611476520 (diff)
Postpone fetching of the data for cached results
This way if an object of the same type is loaded in between iteration, the fetched image won't be messed up.
Diffstat (limited to 'odb/mysql/result.txx')
-rw-r--r--odb/mysql/result.txx95
1 files changed, 68 insertions, 27 deletions
diff --git a/odb/mysql/result.txx b/odb/mysql/result.txx
index 4b18abc..e3ef10b 100644
--- a/odb/mysql/result.txx
+++ b/odb/mysql/result.txx
@@ -3,6 +3,7 @@
// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
// license : GNU GPL v2; see accompanying LICENSE file
+#include <odb/exceptions.hxx>
#include <odb/cache-traits.hxx>
namespace odb
@@ -21,15 +22,18 @@ namespace odb
object_statements<object_type>& statements)
: odb::result_impl<T> (statements.connection ().database ()),
statement_ (statement),
- statements_ (statements)
+ statements_ (statements),
+ count_ (0)
{
- next ();
}
template <typename T>
void result_impl<T>::
load (object_type& obj)
{
+ if (count_ > statement_->fetched ())
+ fetch ();
+
// This is a top-level call so the statements cannot be locked.
//
assert (!statements_.locked ());
@@ -45,6 +49,9 @@ namespace odb
typename result_impl<T>::id_type result_impl<T>::
load_id ()
{
+ if (count_ > statement_->fetched ())
+ fetch ();
+
return object_traits::id (statements_.image ());
}
@@ -54,8 +61,25 @@ namespace odb
{
this->current (pointer_type ());
- // If the result was cached the image can grow between calls
- // to next() as a result of other statements execution.
+ // If we are cached, simply increment the position and
+ // postpone the actual row fetching until later. This way
+ // if the same object is loaded in between iteration, the
+ // image won't be messed up.
+ //
+ count_++;
+
+ if (statement_->cached ())
+ this->end_ = count_ > statement_->result_size ();
+ else
+ fetch ();
+ }
+
+ template <typename T>
+ void result_impl<T>::
+ fetch ()
+ {
+ // If the result is cached, the image can grow between calls
+ // to fetch() as a result of other statements execution.
//
if (statement_->cached ())
{
@@ -70,33 +94,41 @@ namespace odb
}
}
- select_statement::result r (statement_->fetch ());
-
- switch (r)
+ while (count_ > statement_->fetched ())
{
- case select_statement::truncated:
+ select_statement::result r (statement_->fetch ());
+
+ switch (r)
{
- typename object_traits::image_type& im (statements_.image ());
- object_traits::grow (im, statements_.out_image_error ());
+ case select_statement::truncated:
+ {
+ // Don't re-fetch data we are skipping.
+ //
+ if (count_ != statement_->fetched ())
+ continue;
+
+ typename object_traits::image_type& im (statements_.image ());
+ object_traits::grow (im, statements_.out_image_error ());
- if (im.version != statements_.out_image_version ())
+ if (im.version != statements_.out_image_version ())
+ {
+ binding& b (statements_.out_image_binding ());
+ object_traits::bind (b.bind, im, true);
+ statements_.out_image_version (im.version);
+ b.version++;
+ statement_->refetch ();
+ }
+ // Fall throught.
+ }
+ case select_statement::success:
{
- binding& b (statements_.out_image_binding ());
- object_traits::bind (b.bind, im, true);
- statements_.out_image_version (im.version);
- b.version++;
- statement_->refetch ();
+ break;
+ }
+ case select_statement::no_data:
+ {
+ this->end_ = true;
+ break;
}
- // Fall throught.
- }
- case select_statement::success:
- {
- break;
- }
- case select_statement::no_data:
- {
- this->end_ = true;
- break;
}
}
}
@@ -105,13 +137,22 @@ namespace odb
void result_impl<T>::
cache ()
{
- statement_->cache ();
+ if (!statement_->cached ())
+ {
+ statement_->cache ();
+
+ if (count_ >= statement_->result_size ())
+ this->end_ = true;
+ }
}
template <typename T>
std::size_t result_impl<T>::
size ()
{
+ if (!statement_->cached ())
+ throw result_not_cached ();
+
return statement_->result_size ();
}
}