Mailing List
Home
Forum Home
MySQL General - General MySQL discussion
MySQL++ - Programming with the C++ API to MySQL
MaxDB - Everything about MaxDB, formerly known as SAP DB
ODBC - ODBC with the MySQL Connector/ODBC driver
MySQL on Win32 - Runing MySQL on Windows 9x/Me/NT/2000/XP
Java Help - Mostly related to the MySQL Connector/J driver
Perl - Perl support for MySQL with DBI and DBD::mysql
GUI - MySQL GUI Tools
Announcement
Subjects
mysql openssl Question
ERROR 1045: Access denied for user: 'root@localhost ' (Using
password: NO)
Update one field with more fields from another table
Getting Identity after INSERT
ERROR 2002: Can 't connect to local MySQL server through socket
mysql test 4 1 fails with the gis test
MySQL Cluster Software
Downgrade Mysql from 4 to 3 23
Mysql 4 0 Oracle Stored Procedure Trigger Conversion
Can 't access mysql after kernel upgrade
Executing MySQL Commands From Within C Program
Comparing and writing out BLOBS
Preventing Duplicate Entries
FULLTEXT query format question
Strange behavior, Table Level Permission
Does the binary log enabling affect the MySQL performances?
mysql:it 's a db not a dbms how it 's possible?!
mysql have same function mthod as Oracle decode()
 
-none-

-none-

2007-09-25       - By Jim Wallace

 Back
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;
    }
  }


--
MySQL++ Mailing List
For list archives: http://lists.mysql.com/plusplus
To unsubscribe:    http://lists.mysql.com/plusplus?unsub=mysql@(protected)