List:MySQL++« Previous MessageNext Message »
From:Jim Wallace Date:September 25 2007 2:42pm
Subject:Error num in BadQuery patch
View as plain text  
As for background of this, I needed it in two cases.  1) Detecting
duplicate keys, and 2) adding retry logic in the event of a deadlock
(and, yes, I know how and why they should be avoided but fault-tolerant
code is good).  I have created a sample to test this with a deadlock.

Quite simply, this gets the errnum from the API so it can be checked
when a BadQuery exception is caught.  You can not call the connection's
errnum after the exception is thrown since when BadQuery is constructed
it calls the API to get the error as a string, which clears the error
number.

This is against the 2.3.2 codebase since I couldn't get the head of svn
to build.  I'd be happy to re-do the patch against the head if you think
this is a useful feature, after I can build the head.  This is my first
attempt at this, so any constructive criticism is welcome.

jmw



--- connection.cpp	2007-07-11 17:37:16.000000000 -0400
+++ connection.cpp	2007-09-25 07:31:39.000000000 -0400
@@ -300,21 +300,21 @@
 		bool suc = !mysql_reload(&mysql_);
 		if (throw_exceptions() && !suc) {
 			// Reloading grant tables through this API isn't
precisely a
 			// query, but it's acceptable to signal errors
with BadQuery
 			// because the new mechanism is the FLUSH
PRIVILEGES query.
 			// A program won't have to change when doing it
the new way.
-			throw BadQuery(error());
+			throw BadQuery(error(),errnum());
 		}
 		else {
 			return suc;
 		}
 	}
 	else {
 		if (throw_exceptions()) {
-			throw BadQuery("MySQL++ connection not
established");
+			throw BadQuery("MySQL++ connection not
established",errnum());
 		}
 		else {
 			return false;
 		}
 	}
 }
--- exceptions.h	2007-07-11 17:37:16.000000000 -0400
+++ exceptions.h	2007-09-25 08:54:07.000000000 -0400
@@ -242,23 +242,26 @@
 /// SQL query.  In v1.7, it was used as a more generic exception type,
 /// for no particularly good reason.
 
 class MYSQLPP_EXPORT BadQuery : public Exception
 {
 public:
-	/// \brief Create exception object, taking C string
-	explicit BadQuery(const char* w = "") :
-	Exception(w)
+	int	errnum;	///< error number associated with execption
+	
+	/// \brief Create exception object, taking C string and error
number
+	explicit BadQuery(const char* w = "", int err = 0) :
+	Exception(w), errnum(err)
 	{
 	}
 
-	/// \brief Create exception object, taking C++ string
-	explicit BadQuery(const std::string& w) :
-	Exception(w)
+	/// \brief Create exception object, taking C++ string and error
number
+	explicit BadQuery(const std::string& w, int err = 0) :
+	Exception(w), errnum(err)
 	{
 	}
+	
 };
 
 
 /// \brief Exception thrown when there is a problem establishing the
 /// database server connection.  It's also thrown if
 /// Connection::shutdown() fails.
--- query.cpp	2007-07-11 17:37:16.000000000 -0400
+++ query.cpp	2007-09-25 09:05:12.000000000 -0400
@@ -81,13 +81,12 @@
 my_ulonglong
 Query::affected_rows() const
 {
 	return conn_->affected_rows();
 }
 
-
 std::string
 Query::error()
 {
 	return conn_->error();
 }
 
@@ -95,13 +94,13 @@
 bool
 Query::exec(const std::string& str)
 {
 	success_ = !mysql_real_query(&conn_->mysql_, str.data(),
 			static_cast<unsigned long>(str.length()));
 	if (!success_ && throw_exceptions()) {
-		throw BadQuery(error());
+		throw BadQuery(error(),errnum());
 	}
 	else {
 		return success_;
 	}
 }
 
@@ -149,13 +148,13 @@
 
 	unlock();
 	if (success_) {
 		return ResNSel(conn_);
 	}
 	else if (throw_exceptions()) {
-		throw BadQuery(error());
+		throw BadQuery(error(),errnum());
 	}
 	else {
 		return ResNSel();
 	}
 }
 
@@ -463,13 +462,13 @@
 	// that doesn't always return results.  While it's better to use

 	// exec*() in that situation, it's legal to call store()
instead,
 	// and sometimes you have no choice.  For example, if the SQL
comes
 	// from outside the program so you can't predict whether there
will
 	// be results.
 	if (conn_->errnum() && throw_exceptions()) {
-		throw BadQuery(error());
+		throw BadQuery(error(),errnum());
 	}
 	else {
 		return Result();
 	}
 }
 
@@ -510,25 +509,25 @@
 		else {
 			// Result set is null, but throw an exception
only i it is
 			// null because of some error.  If not, it's
just an empty
 			// result set, which is harmless.  We return an
empty result
 			// set if exceptions are disabled, as well.
 			if (conn_->errnum() && throw_exceptions()) {
-				throw BadQuery(error());
+				throw BadQuery(error(),errnum());
 			} 
 			else {
 				return Result();
 			}
 		}
 	}
 	else {
 		// No more results, or some other error occurred.
 		unlock();
 		if (throw_exceptions()) {
 			if (ret > 0) {
-				throw BadQuery(error());
+				throw BadQuery(error(),errnum());
 			}
 			else {
 				throw EndOfResultSets();
 			}
 		}
 		else {
@@ -630,13 +629,13 @@
 	// that doesn't always return results.  While it's better to use

 	// exec*() in that situation, it's legal to call use() instead,
and
 	// sometimes you have no choice.  For example, if the SQL comes
 	// from outside the program so you can't predict whether there
will
 	// be results.
 	if (conn_->errnum() && throw_exceptions()) {
-		throw BadQuery(error());
+		throw BadQuery(error(),errnum());
 	}
 	else {
 		return ResUse();
 	}
 }
 
--- query.h	2007-07-11 17:37:16.000000000 -0400
+++ query.h	2007-09-25 08:53:49.000000000 -0400
@@ -150,12 +150,20 @@
 	/// \brief Assign another query's state to this object
 	///
 	/// The same caveats apply to this operator as apply to the copy
 	/// ctor.
 	Query& operator=(const Query& rhs);
 
+	/// \brief Get the last error number.
+	///
+	/// This just delegates to Connection::errnum().  Query has
nothing
+	/// extra to say, so use either, as makes sense in your program.
+	/// If you want the string *and* number you must 
+	/// call errnum() before calling error() since error() clears
errnum()
+	int errnum() const { return conn_->errnum(); }
+
 	/// \brief Get the last error message that was set.
 	///
 	/// This class has an internal error message string, but if it
 	/// isn't set, we return the last error message that happened
 	/// on the connection we're bound to instead.
 	std::string error();
--- result.h	2007-07-11 17:37:16.000000000 -0400
+++ result.h	2007-09-25 09:04:38.000000000 -0400
@@ -35,12 +35,14 @@
 #include "field_names.h"
 #include "field_types.h"
 #include "noexceptions.h"
 #include "resiter.h"
 #include "row.h"
 
+#include <mysqld_error.h>
+
 #include <map>
 #include <set>
 #include <string>
 
 namespace mysqlpp {
 
@@ -103,13 +105,13 @@
 	/// This is not a thin wrapper. It does a lot of error checking
before
 	/// returning the mysqlpp::Row object containing the row data.
 	Row fetch_row()
 	{
 		if (!result_) {
 			if (throw_exceptions()) {
-				throw BadQuery("Results not fetched");
+				throw BadQuery("Results not
fetched",ER_UNKNOWN_ERROR);
 			}
 			else {
 				return Row();
 			}
 		}
 		MYSQL_ROW row = mysql_fetch_row(result_);
@@ -370,13 +372,13 @@
 	/// \link mysqlpp::ResUse parent class \endlink . Why this
cannot
 	/// actually \e be in our parent class is beyond me.
 	const Row fetch_row() const
 	{
 		if (!result_) {
 			if (throw_exceptions()) {
-				throw BadQuery("Results not fetched");
+				throw BadQuery("Results not
fetched",ER_UNKNOWN_ERROR);
 			}
 			else {
 				return Row();
 			}
 		}
 		MYSQL_ROW row = mysql_fetch_row(result_);
--- row.cpp	2007-07-11 17:37:16.000000000 -0400
+++ row.cpp	2007-09-25 08:56:16.000000000 -0400
@@ -35,13 +35,13 @@
 OptionalExceptions(te),
 res_(r),
 initialized_(false)
 {
 	if (!d || !r) {
 		if (throw_exceptions()) {
-			throw BadQuery("ROW or RES is NULL");
+		throw BadQuery("ROW or RES is
NULL",ER_INVALID_USE_OF_NULL);
 		}
 		else {
 			return;
 		}
 	}
 
Thread
RELEASE: v2.3.2Warren Young11 Jul
  • Getting errnum() in exception?Jim Wallace20 Sep
    • Re: Getting errnum() in exception?Warren Young22 Sep
  • Building the head of SVN with MSVC?Jim Wallace25 Sep
    • Re: Building the head of SVN with MSVC?Warren Young26 Sep
  • Error num in BadQuery patchJim Wallace25 Sep
    • RE: Error num in BadQuery patchJim Wallace26 Sep
      • Re: Error num in BadQuery patchWarren Young26 Sep
    • Re: Error num in BadQuery patchWarren Young26 Sep
  • v2.3.2 and execute?Jim Wallace5 Oct
    • Re: v2.3.2 and execute?Warren Young5 Oct
  • Building svn tip on WindowsJim Wallace24 Oct
    • Re: Building svn tip on WindowsWarren Young25 Oct
  • Patch for better exception use -- BadQuery w/Errnum patch part 1Jim Wallace24 Oct
  • Better exception usage -- BadQuery w/Errnum patch part 2Jim Wallace24 Oct
  • Expose errnum() in query -- BadQuery w/Errnum patch part 3Jim Wallace24 Oct
    • Re: Expose errnum() in query -- BadQuery w/Errnum patch part 3Warren Young25 Oct
      • RE: Expose errnum() in query -- BadQuery w/Errnum patch part 3Jim Wallace25 Oct
  • BadQuery w/Errnum patch part 4Jim Wallace24 Oct
    • Re: BadQuery w/Errnum patch part 4Warren Young25 Oct
      • RE: BadQuery w/Errnum patch part 4Jim Wallace25 Oct
  • Sample files -- BadQuery w/Errnum patch part 4Jim Wallace24 Oct
    • Re: Sample files -- BadQuery w/Errnum patch part 4Warren Young25 Oct
      • RE: Sample files -- BadQuery w/Errnum patch part 4Jim Wallace25 Oct
        • Re: Sample files -- BadQuery w/Errnum patch part 4Warren Young25 Oct
          • RE: Sample files -- BadQuery w/Errnum patch part 4Jim Wallace25 Oct
          • RE: Sample files -- BadQuery w/Errnum patch part 4Jim Wallace25 Oct
            • Re: Sample files -- BadQuery w/Errnum patch part 4Warren Young25 Oct
              • RE: Sample files -- BadQuery w/Errnum patch part 4Jim Wallace25 Oct
      • RE: Sample files -- BadQuery w/Errnum patch part 4Jim Wallace25 Oct