From 61fc247f34255796f5535b52626074b4f92b6bb4 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 26 Nov 2010 15:48:28 +0200 Subject: 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. --- odb/mysql/result.hxx | 7 ++++ odb/mysql/result.txx | 95 +++++++++++++++++++++++++++++++++++-------------- odb/mysql/statement.cxx | 29 +++++---------- 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 +#include // std::size_t + #include #include @@ -56,8 +58,13 @@ namespace odb using odb::result_impl::current; private: + void + fetch (); + + private: details::shared_ptr statement_; object_statements& 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 #include namespace odb @@ -21,15 +22,18 @@ namespace odb object_statements& statements) : odb::result_impl (statements.connection ().database ()), statement_ (statement), - statements_ (statements) + statements_ (statements), + count_ (0) { - next (); } template void result_impl:: 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::id_type result_impl:: 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 + void result_impl:: + 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:: cache () { - statement_->cache (); + if (!statement_->cached ()) + { + statement_->cache (); + + if (count_ >= statement_->result_size ()) + this->end_ = true; + } } template std::size_t result_impl:: 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 (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 (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_; -- cgit v1.1