aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2011-11-02 10:18:25 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2011-11-02 10:18:25 +0200
commit1d5d4d47a0d38dc09302f0430008ddc8ad221add (patch)
tree09a42770e5ee68aa412a0211fa39ff5cf3be6388
parent9eb1da8464db999d520b8739282cbe2b28da0432 (diff)
Prevent potential image overwrite in MySQL query result
-rw-r--r--odb/mysql/object-result.hxx2
-rw-r--r--odb/mysql/object-result.txx29
-rw-r--r--odb/mysql/statement.cxx8
-rw-r--r--odb/mysql/statement.hxx6
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<select_statement> 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 <typename T>
void object_result_impl<T>::
- 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 <typename T>
void object_result_impl<T>::
- 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<my_ulonglong> (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 ();