From 1d5d4d47a0d38dc09302f0430008ddc8ad221add Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 2 Nov 2011 10:18:25 +0200 Subject: Prevent potential image overwrite in MySQL query result --- odb/mysql/object-result.hxx | 2 +- odb/mysql/object-result.txx | 29 ++++++++++++++++++++++++----- odb/mysql/statement.cxx | 8 +++++++- odb/mysql/statement.hxx | 6 +++++- 4 files changed, 37 insertions(+), 8 deletions(-) diff --git a/odb/mysql/object-result.hxx b/odb/mysql/object-result.hxx index 30d0eee..896fc9d 100644 --- a/odb/mysql/object-result.hxx +++ b/odb/mysql/object-result.hxx @@ -60,7 +60,7 @@ namespace odb private: void - fetch (); + fetch (bool next = true); private: details::shared_ptr statement_; diff --git a/odb/mysql/object-result.txx b/odb/mysql/object-result.txx index 502cb8c..1506d96 100644 --- a/odb/mysql/object-result.txx +++ b/odb/mysql/object-result.txx @@ -36,10 +36,17 @@ namespace odb template void object_result_impl:: - load (object_type& obj, bool) + load (object_type& obj, bool f) { if (count_ > statement_->fetched ()) fetch (); + else if (f && statement_->cached ()) + { + // We have to re-load the image in case it has been overwritten + // between the last time we fetched and this call to load(). + // + fetch (false); + } // This is a top-level call so the statements cannot be locked. // @@ -79,6 +86,13 @@ namespace odb { if (count_ > statement_->fetched ()) fetch (); + else if (statement_->cached ()) + { + // We have to re-load the image in case it has been overwritten + // between the last time we fetched and this call to load_id(). + // + fetch (false); + } return object_traits::id (statements_.image ()); } @@ -104,7 +118,7 @@ namespace odb template void object_result_impl:: - fetch () + fetch (bool next) { // If the result is cached, the image can grow between calls // to fetch() as a result of other statements execution. @@ -122,9 +136,9 @@ namespace odb } } - while (!this->end_ && count_ > statement_->fetched ()) + while (!this->end_ && (!next || count_ > statement_->fetched ())) { - select_statement::result r (statement_->fetch ()); + select_statement::result r (statement_->fetch (next)); switch (r) { @@ -132,7 +146,7 @@ namespace odb { // Don't re-fetch data we are skipping. // - if (count_ != statement_->fetched ()) + if (next && count_ != statement_->fetched ()) continue; typename object_traits::image_type& im (statements_.image ()); @@ -161,6 +175,11 @@ namespace odb break; } } + + // If we are refetching the current row, then we are done. + // + if (!next) + break; } } diff --git a/odb/mysql/statement.cxx b/odb/mysql/statement.cxx index 4cd6f35..d4e4943 100644 --- a/odb/mysql/statement.cxx +++ b/odb/mysql/statement.cxx @@ -146,7 +146,7 @@ namespace odb } select_statement::result select_statement:: - fetch () + fetch (bool next) { if (result_version_ != result_.version) { @@ -163,6 +163,12 @@ namespace odb result_version_ = result_.version; } + if (!next && rows_ != 0) + { + assert (cached_); + mysql_stmt_data_seek (stmt_, static_cast (rows_ - 1)); + } + int r (mysql_stmt_fetch (stmt_)); switch (r) diff --git a/odb/mysql/statement.hxx b/odb/mysql/statement.hxx index ec128f2..93adea4 100644 --- a/odb/mysql/statement.hxx +++ b/odb/mysql/statement.hxx @@ -97,8 +97,12 @@ namespace odb return rows_; } + // Fetch next or current row depending on the next argument. + // Note that fetching of the current row is only supported + // if the result is cached. + // result - fetch (); + fetch (bool next = true); void refetch (); -- cgit v1.1