Hi all,

I've been using SOCI within a project I'm working on. So first things
first, thanks to all SOCI developers for this really easy to use but
yet powerful library !

Unfortunately I found what I believe to be a bug. When using prepared
statements with ORM, values aren't updated. Here's a sample code to
explain my issue :

-->
struct foo
{
  int i;
};

namespace soci
{
  template <>
  struct type_conversion<foo>
  {
    typedef values base_type;
    static void from_base(const values&, indicator&, foo&);
    static void to_base(const foo&, values&, indicator&);
  };
}

void soci::type_conversion<foo>::from_base(
  const soci::values& v,
  soci::indicator& ind,
  foo& f)
{
}

void soci::type_conversion<foo>::to_base(
  const foo& f,
  soci::values& v,
  soci::indicator& ind)
{
  v.set("i", f.i);
  return ;
}

int main()
{
  foo bar;

  bar.i = 42;

  soci::session sql(connection_string);
  soci::statement stmt(sql.prepare << "INSERT INTO foo (i) VALUES
(:i)", soci::use(bar));

  while (1)
  {
    bar.i=rand();
    stmt.execute(true);
  }

  return 0;
}
<--

With this code and the latest SOCI version available from the git
repository, the values 42 will be inserted every time the statement is
executed, whereas if the bound variables was from a base type, it
would be updated properly.

So I tried to patch the code to correct this behavior and it _seems_
to work (no leak, no faulty memory access, and of course correct
behavior). What do you think about it ?

Best regards,

-- 
Matthieu KERMAGORET | Développeur

[email protected]

MERETHIS est éditeur du logiciel Centreon.
diff --git a/src/core/statement.cpp b/src/core/statement.cpp
index 738ef6f..49e239a 100644
--- a/src/core/statement.cpp
+++ b/src/core/statement.cpp
@@ -123,6 +123,10 @@ void statement_impl::bind(values & values)
 
             cnt++;
         }
+        for (std::size_t i = selfUsesSize_; i != uses_.size(); ++i)
+        {
+            uses_[i]->pre_use();
+        }
     }
     catch (...)
     {
@@ -532,8 +536,8 @@ void statement_impl::pre_fetch()
 
 void statement_impl::pre_use()
 {
-    std::size_t const usize = uses_.size();
-    for (std::size_t i = 0; i != usize; ++i)
+    selfUsesSize_ = uses_.size();
+    for (std::size_t i = 0; i != selfUsesSize_; ++i)
     {
         uses_[i]->pre_use();
     }
@@ -566,6 +570,8 @@ void statement_impl::post_use(bool gotData)
     {
         uses_[i-1]->post_use(gotData);
     }
+    indicators_.resize(0);
+    uses_.resize(selfUsesSize_);
 }
 
 namespace soci
diff --git a/src/core/statement.h b/src/core/statement.h
index b898a65..528339a 100644
--- a/src/core/statement.h
+++ b/src/core/statement.h
@@ -79,6 +79,7 @@ protected:
 private:
 
     int refCount_;
+    std::size_t selfUsesSize_;
 
     row * row_;
     std::size_t fetchSize_;
diff --git a/src/core/values-exchange.h b/src/core/values-exchange.h
index 249a601..9bde648 100644
--- a/src/core/values-exchange.h
+++ b/src/core/values-exchange.h
@@ -45,19 +45,23 @@ public:
 
     virtual void bind(details::statement_impl & st, int & /*position*/)
     {
+        st_ = &st;
         v_.uppercase_column_names(st.session_.get_uppercase_column_names());
-
-        convert_to_base();
-        st.bind(v_);
     }
 
     virtual void post_use(bool /*gotData*/)
     {
         v_.reset_get_counter();
         convert_from_base();
+        v_.clean_up();
+    }
+
+    virtual void pre_use()
+    {
+        convert_to_base();
+        st.bind(v_);
     }
 
-    virtual void pre_use() {}
     virtual void clean_up() {v_.clean_up();}
     virtual std::size_t size() const { return 1; }
 
@@ -68,6 +72,7 @@ public:
     virtual void convert_from_base() {}
 
 private:
+    details::statement_impl * st_;
     values & v_;
 };
 
diff --git a/src/core/values.h b/src/core/values.h
index 351c79b..61811b3 100644
--- a/src/core/values.h
+++ b/src/core/values.h
@@ -312,20 +312,28 @@ private:
         delete row_;
         row_ = NULL;
 
-        // delete any uses and indicators which were created  by set() but
-        // were not bound by the Statement
-        // (bound uses and indicators are deleted in Statement::clean_up())
-        for (std::map<details::use_type_base *, indicator *>::iterator pos =
-            unused_.begin(); pos != unused_.end(); ++pos)
+        // delete any uses and indicators which were created  by set()
+        for (std::vector<details::standard_use_type *>::iterator it =
+             uses_.begin(); it != uses_.end(); ++it)
         {
-            delete pos->first;
-            delete pos->second;
+          delete *it;
         }
+        uses_.clear();
+
+        for (std::vector<indicator *>::iterator it = indicators_.begin();
+             it != indicators_.end(); ++it)
+        {
+            delete *it;
+        }
+        indicators_.clear();
 
         for (std::size_t i = 0; i != deepCopies_.size(); ++i)
         {
             delete deepCopies_[i];
         }
+        deepCopies_.clear();
+
+        unused_.clear();
     }
 };
 
diff --git a/src/core/statement.cpp b/src/core/statement.cpp
index 738ef6f..49e239a 100644
--- a/src/core/statement.cpp
+++ b/src/core/statement.cpp
@@ -123,6 +123,10 @@ void statement_impl::bind(values & values)
 
             cnt++;
         }
+        for (std::size_t i = selfUsesSize_; i != uses_.size(); ++i)
+        {
+            uses_[i]->pre_use();
+        }
     }
     catch (...)
     {
@@ -532,8 +536,8 @@ void statement_impl::pre_fetch()
 
 void statement_impl::pre_use()
 {
-    std::size_t const usize = uses_.size();
-    for (std::size_t i = 0; i != usize; ++i)
+    selfUsesSize_ = uses_.size();
+    for (std::size_t i = 0; i != selfUsesSize_; ++i)
     {
         uses_[i]->pre_use();
     }
@@ -566,6 +570,8 @@ void statement_impl::post_use(bool gotData)
     {
         uses_[i-1]->post_use(gotData);
     }
+    indicators_.resize(0);
+    uses_.resize(selfUsesSize_);
 }
 
 namespace soci
diff --git a/src/core/statement.h b/src/core/statement.h
index b898a65..528339a 100644
--- a/src/core/statement.h
+++ b/src/core/statement.h
@@ -79,6 +79,7 @@ protected:
 private:
 
     int refCount_;
+    std::size_t selfUsesSize_;
 
     row * row_;
     std::size_t fetchSize_;
diff --git a/src/core/values-exchange.h b/src/core/values-exchange.h
index 249a601..1adc227 100644
--- a/src/core/values-exchange.h
+++ b/src/core/values-exchange.h
@@ -45,19 +45,23 @@ public:
 
     virtual void bind(details::statement_impl & st, int & /*position*/)
     {
+        st_ = &st;
         v_.uppercase_column_names(st.session_.get_uppercase_column_names());
-
-        convert_to_base();
-        st.bind(v_);
     }
 
     virtual void post_use(bool /*gotData*/)
     {
         v_.reset_get_counter();
         convert_from_base();
+        v_.clean_up();
+    }
+
+    virtual void pre_use()
+    {
+        convert_to_base();
+        st_->bind(v_);
     }
 
-    virtual void pre_use() {}
     virtual void clean_up() {v_.clean_up();}
     virtual std::size_t size() const { return 1; }
 
@@ -68,6 +72,7 @@ public:
     virtual void convert_from_base() {}
 
 private:
+    details::statement_impl * st_;
     values & v_;
 };
 
diff --git a/src/core/values.h b/src/core/values.h
index 351c79b..61811b3 100644
--- a/src/core/values.h
+++ b/src/core/values.h
@@ -312,20 +312,28 @@ private:
         delete row_;
         row_ = NULL;
 
-        // delete any uses and indicators which were created  by set() but
-        // were not bound by the Statement
-        // (bound uses and indicators are deleted in Statement::clean_up())
-        for (std::map<details::use_type_base *, indicator *>::iterator pos =
-            unused_.begin(); pos != unused_.end(); ++pos)
+        // delete any uses and indicators which were created  by set()
+        for (std::vector<details::standard_use_type *>::iterator it =
+             uses_.begin(); it != uses_.end(); ++it)
         {
-            delete pos->first;
-            delete pos->second;
+          delete *it;
         }
+        uses_.clear();
+
+        for (std::vector<indicator *>::iterator it = indicators_.begin();
+             it != indicators_.end(); ++it)
+        {
+            delete *it;
+        }
+        indicators_.clear();
 
         for (std::size_t i = 0; i != deepCopies_.size(); ++i)
         {
             delete deepCopies_[i];
         }
+        deepCopies_.clear();
+
+        unused_.clear();
     }
 };
 
------------------------------------------------------------------------------

_______________________________________________
Soci-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/soci-users

Reply via email to