Author: wyoung
Date: Thu Nov 29 11:09:30 2007
New Revision: 1924

URL: http://svn.gna.org/viewcvs/mysqlpp?rev=1924&view=rev
Log:
- Replaced operator bool() in Connection, Query, Row and ResUse with
  a "safe bool" implementation based on bits in Jonathan Wakely's
  proposed RefCountedPointer replacement.  It's essentially the same
  code, which we didn't use in RefCountedPointer, but did find a use for
  here.
- ResUse similarly changed, but instead of having an operator that
  converts itself into "pointer to private data member", it just returns
  the MYSQL_RES*.  One could argue that it's an exposure of internal
  implmementation details, but it was only days ago that we removed
  ResUse::raw_result(), so....   Lacking anything better to return, and
  being unwilling to create something just for information hiding sake,
  we did it this way.
- Bonus of previous item: was able to remove ResUse::operator ==() and
  operator !=().  We get those for free when there's a convert-to-ptr
  operator.
- Changed examples/simple?.cpp to make clearer use of these bool
  context conversions.

Modified:
    trunk/Wishlist
    trunk/examples/simple1.cpp
    trunk/examples/simple2.cpp
    trunk/examples/simple3.cpp
    trunk/lib/connection.h
    trunk/lib/query.h
    trunk/lib/result.h
    trunk/lib/row.h

Modified: trunk/Wishlist
URL: 
http://svn.gna.org/viewcvs/mysqlpp/trunk/Wishlist?rev=1924&r1=1923&r2=1924&view=diff
==============================================================================
--- trunk/Wishlist (original)
+++ trunk/Wishlist Thu Nov 29 11:09:30 2007
@@ -16,10 +16,6 @@
     o The manipulator changes sometime during 2.3 broke the column
       formatting of the examples that dump tables.  A setw(x) call
       results in x spaces, not x - strlen(whatevercamebefore).
-
-    o Classes Connection, Query, String, Result and Row all have
-      operator bool() as well.  Use Jonathan Wakely's "safe bool"
-      instead?
 
     o Atomic inc/dec of reference counts in RefCounted*?
 
@@ -111,6 +107,8 @@
 
     o Add operator<< for Query, syntactic sugar for str(ostream&).
 
+    o Is Row::size_ not redundant w.r.t. Row::data_.size()?
+
 
 v3.0 "Maybe" Stuff
 ------------------

Modified: trunk/examples/simple1.cpp
URL: 
http://svn.gna.org/viewcvs/mysqlpp/trunk/examples/simple1.cpp?rev=1924&r1=1923&r2=1924&view=diff
==============================================================================
--- trunk/examples/simple1.cpp (original)
+++ trunk/examples/simple1.cpp Thu Nov 29 11:09:30 2007
@@ -45,27 +45,26 @@
        }
 
        // Connect to the sample database.
-       mysqlpp::Connection con(false);
-       if (!con.connect(db, server, user, pass)) {
+       mysqlpp::Connection conn(false);
+       if (conn.connect(db, server, user, pass)) {
+               // Retrieve a subset of the sample stock table set up by resetdb
+               // and display it.
+               mysqlpp::Query query = conn.query("select item from stock");
+               if (mysqlpp::Result res = query.store()) {
+                       cout << "We have:" << endl;
+                       for (int i = 0; mysqlpp::Row row = res[i]; ++i) {
+                               cout << '\t' << row[0] << endl;
+                       }
+               }
+               else {
+                       cerr << "Failed to get item list: " << query.error() << 
endl;
+                       return 1;
+               }
+
+               return 0;
+       }
+       else {
+               cerr << "DB connection failed: " << conn.error() << endl;
                return 1;
        }
-
-       // Retrieve a subset of the sample stock table set up by resetdb
-       mysqlpp::Query query = con.query("select item from stock");
-       mysqlpp::Result res = query.store();
-
-       // Display the result set
-       cout << "We have:" << endl;
-       if (res) {
-               mysqlpp::Row row;
-               for (int i = 0; row = res[i]; ++i) {
-                       cout << '\t' << row[0] << endl;
-               }
-       }
-       else {
-               cerr << "Failed to get item list: " << query.error() << endl;
-               return 1;
-       }
-
-       return 0;
 }

Modified: trunk/examples/simple2.cpp
URL: 
http://svn.gna.org/viewcvs/mysqlpp/trunk/examples/simple2.cpp?rev=1924&r1=1923&r2=1924&view=diff
==============================================================================
--- trunk/examples/simple2.cpp (original)
+++ trunk/examples/simple2.cpp Thu Nov 29 11:09:30 2007
@@ -45,40 +45,41 @@
        }
 
        // Connect to the sample database.
-       mysqlpp::Connection con(false);
-       if (!con.connect(db, server, user, pass)) {
+       mysqlpp::Connection conn(false);
+       if (conn.connect(db, server, user, pass)) {
+               // Retrieve the sample stock table set up by resetdb
+               mysqlpp::Query query = conn.query("select * from stock");
+               mysqlpp::Result res = query.store();
+
+               // Display results
+               if (res) {
+                       // Display header
+                       cout.setf(ios::left);
+                       cout << setw(31) << "Item" <<
+                                       setw(10) << "Num" <<
+                                       setw(10) << "Weight" <<
+                                       setw(10) << "Price" <<
+                                       "Date" << endl << endl;
+
+                       // Get each row in result set, and print its contents
+                       for (int i = 0; mysqlpp::Row row = res[i]; ++i) {
+                               cout << setw(30) << row["item"] << ' ' <<
+                                               setw(9) << row["num"] << ' ' <<
+                                               setw(9) << row["weight"] << ' ' 
<<
+                                               setw(9) << row["price"] << ' ' 
<<
+                                               setw(9) << row["sdate"] <<
+                                               endl;
+                       }
+               }
+               else {
+                       cerr << "Failed to get stock table: " << query.error() 
<< endl;
+                       return 1;
+               }
+
+               return 0;
+       }
+       else {
+               cerr << "DB connection failed: " << conn.error() << endl;
                return 1;
        }
-
-       // Retrieve the sample stock table set up by resetdb
-       mysqlpp::Query query = con.query("select * from stock");
-       mysqlpp::Result res = query.store();
-
-       // Display results
-       if (res) {
-               // Display header
-               cout.setf(ios::left);
-               cout << setw(31) << "Item" <<
-                               setw(10) << "Num" <<
-                               setw(10) << "Weight" <<
-                               setw(10) << "Price" <<
-                               "Date" << endl << endl;
-
-               // Get each row in result set, and print its contents
-               mysqlpp::Row row;
-               for (int i = 0; row = res[i]; ++i) {
-                       cout << setw(30) << row["item"] << ' ' <<
-                                       setw(9) << row["num"] << ' ' <<
-                                       setw(9) << row["weight"] << ' ' <<
-                                       setw(9) << row["price"] << ' ' <<
-                                       setw(9) << row["sdate"] <<
-                                       endl;
-               }
-       }
-       else {
-               cerr << "Failed to get stock table: " << query.error() << endl;
-               return 1;
-       }
-
-       return 0;
 }

Modified: trunk/examples/simple3.cpp
URL: 
http://svn.gna.org/viewcvs/mysqlpp/trunk/examples/simple3.cpp?rev=1924&r1=1923&r2=1924&view=diff
==============================================================================
--- trunk/examples/simple3.cpp (original)
+++ trunk/examples/simple3.cpp Thu Nov 29 11:09:30 2007
@@ -45,41 +45,41 @@
        }
 
        // Connect to the sample database.
-       mysqlpp::Connection con(false);
-       if (!con.connect(db, server, user, pass)) {
-               return 1;
-       }
+       mysqlpp::Connection conn(false);
+       if (conn.connect(db, server, user, pass)) {
+               // Ask for all rows from the sample stock table and display
+               // them.  Unlike simple2 example, we retreive each row one at
+               // a time instead of storing the entire result set in memory
+               // and then iterating over it.
+               mysqlpp::Query query = conn.query("select * from stock");
+               if (mysqlpp::ResUse res = query.use()) {
+                       // Display header
+                       cout.setf(ios::left);
+                       cout << setw(31) << "Item" <<
+                                       setw(10) << "Num" <<
+                                       setw(10) << "Weight" <<
+                                       setw(10) << "Price" <<
+                                       "Date" << endl << endl;
 
-       // Ask for all rows from the sample stock table set up by resetdb.
-       // Unlike simple2 example, we don't store result set in memory.
-       mysqlpp::Query query = con.query("select * from stock");
-       mysqlpp::ResUse res = query.use();
+                       // Get each row in result set, and print its contents
+                       while (mysqlpp::Row row = res.fetch_row()) {
+                               cout << setw(30) << row["item"] << ' ' <<
+                                               setw(9) << row["num"] << ' ' <<
+                                               setw(9) << row["weight"] << ' ' 
<<
+                                               setw(9) << row["price"] << ' ' 
<<
+                                               setw(9) << row["sdate"] <<
+                                               endl;
+                       }
 
-       // Retreive result rows one by one, and display them.
-       if (res) {
-               // Display header
-               cout.setf(ios::left);
-               cout << setw(31) << "Item" <<
-                               setw(10) << "Num" <<
-                               setw(10) << "Weight" <<
-                               setw(10) << "Price" <<
-                               "Date" << endl << endl;
-
-               // Get each row in result set, and print its contents
-               mysqlpp::Row row;
-               while (row = res.fetch_row()) {
-                       cout << setw(30) << row["item"] << ' ' <<
-                                       setw(9) << row["num"] << ' ' <<
-                                       setw(9) << row["weight"] << ' ' <<
-                                       setw(9) << row["price"] << ' ' <<
-                                       setw(9) << row["sdate"] <<
-                                       endl;
+                       return 0;
                }
-
-               return 0;
+               else {
+                       cerr << "Failed to get stock item: " << query.error() 
<< endl;
+                       return 1;
+               }
        }
        else {
-               cerr << "Failed to get stock item: " << query.error() << endl;
+               cerr << "DB connection failed: " << conn.error() << endl;
                return 1;
        }
 }

Modified: trunk/lib/connection.h
URL: 
http://svn.gna.org/viewcvs/mysqlpp/trunk/lib/connection.h?rev=1924&r1=1923&r2=1924&view=diff
==============================================================================
--- trunk/lib/connection.h (original)
+++ trunk/lib/connection.h Thu Nov 29 11:09:30 2007
@@ -53,6 +53,13 @@
 
 class MYSQLPP_EXPORT Connection : public OptionalExceptions
 {
+private:
+       /// \brief Pointer to bool data member, for use by safe bool
+       /// conversion operator.
+       ///
+       /// \see http://www.artima.com/cppsource/safebool.html
+    typedef bool Connection::*private_bool_type;
+
 public:
        /// \brief Legal types of option arguments
        enum OptionArgType {
@@ -308,27 +315,29 @@
                return mysql_kill(&mysql_, tid);
        }
 
-       /// \brief Test whether the connection has experienced an error
-       /// condition.
-       ///
-       /// Allows for code constructs like this:
+       /// \brief Test whether any error has occurred within the object.
+       ///
+       /// Allows the object to be used in bool context, like this:
        ///
        /// \code
        ///     Connection conn;
        ///     .... use conn
        ///     if (conn) {
-       ///         ... last SQL query was successful
+       ///         ... nothing bad has happened since last successful use
        ///     }
        ///     else {
-       ///         ... error occurred in SQL query
+       ///         ... some error has occurred
        ///     }
        /// \endcode
        ///
-       /// Prior to version 3, this function could never return true if
-       /// we weren't connected.  As of version 3, a true return simply
-       /// indicates a lack of errors; call connected() to test whether
-       /// the connection is established.
-       operator bool() const { return copacetic_; }
+       /// Prior to MySQL++ v3, the object was always falsy when we
+       /// weren't connected.  Now a true return simply indicates a lack of
+       /// errors.  If you've been using this to test for whether the
+       /// connection is still up, you need to call connected() instead.
+       operator private_bool_type() const
+       {
+               return copacetic_ ? &Connection::copacetic_ : 0;
+       }
 
        /// \brief Copy an existing Connection object's state into this
        /// object.

Modified: trunk/lib/query.h
URL: 
http://svn.gna.org/viewcvs/mysqlpp/trunk/lib/query.h?rev=1924&r1=1923&r2=1924&view=diff
==============================================================================
--- trunk/lib/query.h (original)
+++ trunk/lib/query.h Thu Nov 29 11:09:30 2007
@@ -121,6 +121,13 @@
         public std::ostream,
                public OptionalExceptions
 {
+private:
+       /// \brief Pointer to bool data member, for use by safe bool
+       /// conversion operator.
+       ///
+       /// \see http://www.artima.com/cppsource/safebool.html
+    typedef bool Query::*private_bool_type;
+
 public:
        /// \brief Create a new query object attached to a connection.
        ///
@@ -164,7 +171,10 @@
        /// This method returns false if either the Query object or its
        /// associated Connection object has seen an error condition since
        /// the last operation.
-       operator bool() const { return *conn_ && copacetic_; }
+       operator private_bool_type() const
+       {
+               return *conn_ && copacetic_ ? &Query::copacetic_ : 0;
+       }
 
        /// \brief Return true if the object has experienced an error
        bool operator !() { return !copacetic_; }

Modified: trunk/lib/result.h
URL: 
http://svn.gna.org/viewcvs/mysqlpp/trunk/lib/result.h?rev=1924&r1=1923&r2=1924&view=diff
==============================================================================
--- trunk/lib/result.h (original)
+++ trunk/lib/result.h Thu Nov 29 11:09:30 2007
@@ -158,20 +158,32 @@
        int num_fields() const
                        { return mysql_num_fields(result_.raw()); }
        
-       /// \brief Return true if we have a valid result set
-       ///
-       /// This operator is primarily used to determine if a query was
+       /// \brief Return the pointer to the underlying MySQL C API
+       /// result set object.
+       ///
+       /// While this has obvious inherent value for those times you need
+       /// to dig beneath the MySQL++ interface, it has subtler value.
+       /// It effectively stands in for operator bool(), operator !(),
+       /// operator ==(), and operator !=(), because the C++ compiler can
+       /// implement all of these with a MYSQL_RES*.
+       ///
+       /// Of these uses, the most valuable is using the ResUse object in
+       /// bool context to determine if the query that created it was
        /// successful:
        ///
        /// \code
        ///   Query q("....");
-       ///   if (q.use()) {
-       ///       ...
+       ///   if (ResUse res = q.use()) {
+       ///       // Can use 'res', query succeeded
+       ///   }
+       ///   else {
+       ///       // Query failed, call Query::error() or ::errnum() for why
+       ///   }
        /// \endcode
-       ///
-       /// Query::use() returns a ResUse object, and it won't contain a
-       /// valid result set if the query failed.
-       operator bool() const { return result_; }
+       operator MYSQL_RES*() const
+       {
+               return result_.raw();
+       }
        
        /// \brief Return the name of the table the result set comes from
        const char* table() const
@@ -204,19 +216,6 @@
 
        /// \brief Get the underlying Field structure given its index.
        const Field& field(unsigned int i) const { return fields_.at(i); }
-       
-       /// \brief Returns true if the other ResUse object shares the same
-       /// underlying C API result set as this one.
-       ///
-       /// This works because the underlying result set is stored as a
-       /// pointer, and thus can be copied and then compared.
-       bool operator ==(const ResUse& other) const
-                       { return result_ == other.result_; } 
-
-       /// \brief Returns true if the other ResUse object has a different
-       /// underlying C API result set from this one.
-       bool operator !=(const ResUse& other) const
-                       { return result_ != other.result_; }
 
 protected:
        bool initialized_;                      ///< if true, object is fully 
initted
@@ -382,6 +381,13 @@
 /// \brief Holds information on queries that don't return data.
 class MYSQLPP_EXPORT ResNSel
 {
+private:
+       /// \brief Pointer to bool data member, for use by safe bool
+       /// conversion operator.
+       ///
+       /// \see http://www.artima.com/cppsource/safebool.html
+    typedef bool ResNSel::*private_bool_type;
+
 public:
        /// \brief Default ctor
        ResNSel() :
@@ -401,8 +407,16 @@
        {
        }
 
-       /// \brief Test whether the query was successful
-       operator bool() const { return copacetic_; }
+       /// \brief Test whether the query that created this result succeeded
+       ///
+       /// If you test this object in bool context and it's false, it's a
+       /// signal that the query this was created from failed in some way.
+       /// Call Query::error() or Query::errnum() to find out what exactly
+       /// happened.
+       operator private_bool_type() const
+       {
+               return copacetic_ ? &ResNSel::copacetic_ : 0;
+       }
 
        /// \brief Get the last value used for an AUTO_INCREMENT field
        my_ulonglong insert_id() const { return insert_id_; }

Modified: trunk/lib/row.h
URL: 
http://svn.gna.org/viewcvs/mysqlpp/trunk/lib/row.h?rev=1924&r1=1923&r2=1924&view=diff
==============================================================================
--- trunk/lib/row.h (original)
+++ trunk/lib/row.h Thu Nov 29 11:09:30 2007
@@ -50,6 +50,13 @@
 /// \brief Manages rows from a result set.
 class MYSQLPP_EXPORT Row : public OptionalExceptions
 {
+private:
+       /// \brief Pointer to bool data member, for use by safe bool
+       /// conversion operator.
+       ///
+       /// \see http://www.artima.com/cppsource/safebool.html
+    typedef bool Row::*private_bool_type;
+
 public:
        typedef int difference_type;                    ///< type for index 
differences
        typedef unsigned int size_type;                 ///< type of returned 
sizes
@@ -152,8 +159,27 @@
        /// supposed to throw an exception, according to the Standard.
        const value_type& at(int i) const { return data_.at(i); }
 
-       /// \brief Returns true if there is data in the row.
-       operator bool() const { return data_.size(); }
+       /// \brief Returns true if row object was fully initialized and
+       /// has data.
+       ///
+       /// This operator lets you use Row in bool context, which lets you
+       /// do things like tell when you've run off the end of a "use"
+       /// query's result set:
+       ///
+       /// \code
+       ///   Query q("....");
+       ///   if (ResUse res = q.use()) {
+       ///       // Can use 'res', query succeeded
+       ///       while (Row row = res.fetch_row()) {
+       ///           // Retreived another row in the result set, can use 'row'
+       ///       }
+       ///   }
+       /// \endcode
+       ///
+       operator private_bool_type() const
+       {
+               return data_.size() && initialized_ ? &Row::initialized_ : 0;
+       }
 
        /// \brief Returns a field's index given its name
        size_type field_num(const char* name) const;


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

Reply via email to