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