Author: wyoung
Date: Wed Nov 28 06:48:58 2007
New Revision: 1907

URL: http://svn.gna.org/viewcvs/mysqlpp?rev=1907&view=rev
Log:
Changed ResUse::result_ and types_ from raw pointers to refcounted
pointers.  This then allowed us to do away with a particularly nasty bit
of trickery that's been present as long as I've been maintaining
MySQL++: in order to make ResUse/Result objects cheap to copy/assign
(happens many places in MySQL++) it wouldn't do a real copy, but rather
a "move": the assignee would be the new owner of all allocated objects,
and the old one would give them up.  These copies are only expected to
happen when MySQL++ methods return ResUse or Result objects to callers;
MySQL++ doesn't go on to use these objects, so it happened to work, but
ICKY POO!

Modified:
    trunk/lib/result.cpp
    trunk/lib/result.h

Modified: trunk/lib/result.cpp
URL: 
http://svn.gna.org/viewcvs/mysqlpp/trunk/lib/result.cpp?rev=1907&r1=1906&r2=1907&view=diff
==============================================================================
--- trunk/lib/result.cpp (original)
+++ trunk/lib/result.cpp Wed Nov 28 06:48:58 2007
@@ -30,9 +30,7 @@
 
 ResUse::ResUse(MYSQL_RES* result, bool te) :
 OptionalExceptions(te),
-result_(0),
 initialized_(false),
-types_(0),
 fields_(this)
 {
        if (result) {
@@ -46,37 +44,25 @@
 
 ResUse::~ResUse()
 {
-       purge();
 }
 
 
 void
 ResUse::copy(const ResUse& other)
 {
-       if (initialized_) {
-               purge();
-       }
-
        set_exceptions(other.throw_exceptions());
 
        if (other.result_) {
                result_ = other.result_;
                fields_ = Fields(this);
                names_ = other.names_;
-               
-               if (other.types_) {
-                       types_ = new FieldTypes(*other.types_);
-               }
-               else {
-                       types_ = 0;
-               }
-
+               types_ = other.types_;
                initialized_ = true;
        }
        else {
                result_ = 0;
+               names_ = 0;
                types_ = 0;
-               names_ = 0;
                initialized_ = other.initialized_;
        }
 }
@@ -94,29 +80,12 @@
 }
 
 
-void
-ResUse::purge()
-{
-       if (result_) {
-               mysql_free_result(result_);
-               result_ = 0;
-       }
-
-       names_ = 0;
-
-       delete types_;
-       types_ = 0;
-}
-
-
 ResUse&
 ResUse::operator =(const ResUse& other)
 {
-       if (this == &other) {
-               return *this;
+       if (this != &other) {
+               copy(other);
        }
-       copy(other);
-       other.result_ = 0;
        return *this;
 }
 

Modified: trunk/lib/result.h
URL: 
http://svn.gna.org/viewcvs/mysqlpp/trunk/lib/result.h?rev=1907&r1=1906&r2=1907&view=diff
==============================================================================
--- trunk/lib/result.h (original)
+++ trunk/lib/result.h Wed Nov 28 06:48:58 2007
@@ -40,6 +40,25 @@
 #include "subiter.h"
 
 namespace mysqlpp {
+
+/// \brief Functor to call mysql_free_result() on the pointer you pass
+/// to it.
+///
+/// This overrides RefCountedPointer's default destroyer, which uses
+/// operator delete; it annoys the C API when you nuke its data
+/// structures this way. :)
+template <>
+struct RefCountedPointerDestroyer<MYSQL_RES>
+{
+       /// \brief Functor implementation
+       void operator()(MYSQL_RES* doomed)
+       {
+               if (doomed) {
+                       mysql_free_result(doomed);
+               }
+       }
+};
+
 
 /// \brief A basic result set class, for use with "use" queries.
 ///
@@ -57,9 +76,7 @@
        /// \brief Default constructor
        ResUse() :
        OptionalExceptions(),
-       result_(0),
        initialized_(false),
-       types_(0),
        fields_(this)
        {
        }
@@ -73,7 +90,6 @@
        initialized_(false)
        {
                copy(other);
-               other.result_ = 0;
        }
        
        /// \brief Destroy object
@@ -123,20 +139,24 @@
        /// It is anticipated that this is only useful within the library,
        /// to implement higher-level query types on top of raw "use"
        /// queries. Query::storein() uses it, for example.
-       MYSQL_ROW fetch_raw_row() const { return mysql_fetch_row(result_); }
+       MYSQL_ROW fetch_raw_row() const
+                       { return mysql_fetch_row(result_.raw()); }
 
        /// \brief Wraps mysql_fetch_lengths() in MySQL C API.
        const unsigned long* fetch_lengths() const
-                       { return mysql_fetch_lengths(result_); }
+                       { return mysql_fetch_lengths(result_.raw()); }
 
        /// \brief Wraps mysql_fetch_field() in MySQL C API.
-       const Field& fetch_field() const { return *mysql_fetch_field(result_); }
+       const Field& fetch_field() const
+                       { return *mysql_fetch_field(result_.raw()); }
 
        /// \brief Wraps mysql_field_seek() in MySQL C API.
-       void field_seek(int field) { mysql_field_seek(result_, field); }
+       void field_seek(int field) const
+                       { mysql_field_seek(result_.raw(), field); }
 
        /// \brief Wraps mysql_num_fields() in MySQL C API.
-       int num_fields() const { return mysql_num_fields(result_); }
+       int num_fields() const
+                       { return mysql_num_fields(result_.raw()); }
        
        /// \brief Return true if we have a valid result set
        ///
@@ -167,16 +187,17 @@
                        { return names_->at(i); }
 
        /// \brief Get the names of the fields within this result set.
-       const RefCountedPointer<FieldNames> field_names() const
+       const RefCountedPointer<FieldNames>& field_names() const
                        { return names_; }
 
        /// \brief Get the MySQL type for a field given its index.
        const mysql_type_info& field_type(int i) const
-                       { return (*types_)[i]; }
+                       { return types_->at(i); }
 
        /// \brief Get a list of the types of the fields within this
        /// result set.
-       const FieldTypes& field_types() const { return *types_; }
+       const RefCountedPointer<FieldTypes>& field_types() const
+                       { return types_; }
 
        /// \brief Get the underlying Fields structure.
        const Fields& fields() const { return fields_; }
@@ -198,24 +219,37 @@
                        { return result_ != other.result_; }
 
 protected:
-       mutable MYSQL_RES* result_;     ///< underlying C API result set
        bool initialized_;                      ///< if true, object is fully 
initted
-       FieldTypes* types_;                     ///< list of field types in 
result
        Fields fields_;                         ///< list of fields in result
+
+       /// \brief underlying C API result set
+       ///
+       /// This is mutable because so many methods in this class and in
+       /// Result are justifiably const, but they call C API methods that
+       /// take non-const MYSQL_RES*.  It's possible (likely even, in many
+       /// cases) that these functions do modify the MYSQL_RES object
+       /// which is part of this object, so strict constness says this
+       /// object changed, too, but this has always been mutable and the
+       /// resulting behavior hasn't confused anyone yet.  I think this is
+       /// because people the methods likely to change the C API object are
+       /// those used in "use" queries, but MySQL++ users tend to treat
+       /// ResUse objects the same as Result objects: it's a convenient
+       /// fiction that the entire result set is present in both cases, so
+       /// the act of fetching new rows is an implementation detail that
+       /// doesn't modify the function of the object.  Thus, it is
+       /// effectively still const.
+       mutable RefCountedPointer<MYSQL_RES> result_;
 
        /// \brief list of field names in result
        RefCountedPointer<FieldNames> names_;
 
+       /// \brief list of field types in result
+       RefCountedPointer<FieldTypes> types_;
+
        /// \brief Copy another ResUse object's contents into this one.
        ///
        /// Self-copy is not allowed.
        void copy(const ResUse& other);
-
-       /// \brief Free all resources held by the object.
-       ///
-       /// This exists just to do things common to both copy() and the
-       /// dtor, both of which need to free allocated resources.
-       void purge();
 };
 
 
@@ -303,23 +337,17 @@
        /// \brief Wraps mysql_num_rows() in MySQL C API.
        my_ulonglong num_rows() const
        {
-               if (initialized_)
-                       return mysql_num_rows(result_);
-               else
-                       return 0;
+               return initialized_ ? mysql_num_rows(result_.raw()) : 0;
        }
 
        /// \brief Wraps mysql_data_seek() in MySQL C API.
        void data_seek(uint offset) const
        {
-               mysql_data_seek(result_, offset);
+               mysql_data_seek(result_.raw(), offset);
        }
 
        /// \brief Alias for num_rows(), only with different return type.
-       size_type size() const
-       {
-               return size_type(num_rows());
-       }
+       size_type size() const { return static_cast<size_type>(num_rows()); }
 
        /// \brief Get the row with an offset of i.
        const value_type at(int i) const


_______________________________________________
Mysqlpp-commits mailing list
[email protected]
https://mail.gna.org/listinfo/mysqlpp-commits

Reply via email to