diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2010-11-26 15:48:28 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2010-11-26 15:48:28 +0200 |
commit | 61fc247f34255796f5535b52626074b4f92b6bb4 (patch) | |
tree | 347d00cedcee85f7d75a5976a210ab07ef33c7be | |
parent | ba8430c002627705d559b5dd9d78ae7611476520 (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.hxx | 7 | ||||
-rw-r--r-- | odb/mysql/result.txx | 95 | ||||
-rw-r--r-- | odb/mysql/statement.cxx | 29 | ||||
-rw-r--r-- | odb/mysql/statement.hxx | 16 |
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_; |