aboutsummaryrefslogtreecommitdiff
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
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.
-rw-r--r--odb/mysql/result.hxx7
-rw-r--r--odb/mysql/result.txx95
-rw-r--r--odb/mysql/statement.cxx29
-rw-r--r--odb/mysql/statement.hxx16
4 files changed, 99 insertions, 48 deletions
diff --git a/odb/mysql/result.hxx b/odb/mysql/result.hxx
index ec232a5..5c1e185 100644
--- a/odb/mysql/result.hxx
+++ b/odb/mysql/result.hxx
@@ -8,6 +8,8 @@
#include <odb/pre.hxx>
+#include <cstddef> // std::size_t
+
#include <odb/result.hxx>
#include <odb/mysql/version.hxx>
@@ -56,8 +58,13 @@ namespace odb
using odb::result_impl<T>::current;
private:
+ void
+ fetch ();
+
+ private:
details::shared_ptr<select_statement> statement_;
object_statements<object_type>& statements_;
+ std::size_t count_;
};
}
}
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 ();
}
}
diff --git a/odb/mysql/statement.cxx b/odb/mysql/statement.cxx
index 0f21917..6edfa16 100644
--- a/odb/mysql/statement.cxx
+++ b/odb/mysql/statement.cxx
@@ -126,27 +126,20 @@ namespace odb
if (!end_)
{
if (mysql_stmt_store_result (stmt_))
- {
throw database_exception (stmt_);
- }
+
+ // mysql_stmt_num_rows() returns the number of rows that have been
+ // fetched by store_result.
+ //
+ size_ = rows_ + static_cast<size_t> (mysql_stmt_num_rows (stmt_));
}
+ else
+ size_ = rows_;
cached_ = true;
}
}
- std::size_t select_statement::
- result_size ()
- {
- if (!cached_)
- throw result_not_cached ();
-
- // mysql_stmt_num_rows() returns the number of rows that have been
- // fetched by store_result.
- //
- return rows_ + static_cast<std::size_t> (mysql_stmt_num_rows (stmt_));
- }
-
select_statement::result select_statement::
fetch ()
{
@@ -167,9 +160,7 @@ namespace odb
{
case 0:
{
- if (!cached_)
- rows_++;
-
+ rows_++;
return success;
}
case MYSQL_NO_DATA:
@@ -179,9 +170,7 @@ namespace odb
}
case MYSQL_DATA_TRUNCATED:
{
- if (!cached_)
- rows_++;
-
+ rows_++;
return truncated;
}
default:
diff --git a/odb/mysql/statement.hxx b/odb/mysql/statement.hxx
index 343595d..5ff0a4e 100644
--- a/odb/mysql/statement.hxx
+++ b/odb/mysql/statement.hxx
@@ -76,8 +76,21 @@ namespace odb
return cached_;
}
+ // Can only be called on a cached result.
+ //
+ std::size_t
+ result_size () const
+ {
+ return size_;
+ }
+
+ // Number of rows already fetched.
+ //
std::size_t
- result_size ();
+ fetched () const
+ {
+ return rows_;
+ }
result
fetch ();
@@ -99,6 +112,7 @@ namespace odb
bool end_;
bool cached_;
std::size_t rows_;
+ std::size_t size_;
binding& cond_;
std::size_t cond_version_;