aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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_;