Hi, I've noticed a serious bug that was introduced in
MySQL++ v2.0.0 when the Query class was changed to derive
from std::ostream.
Per the C++ standard, regardless of the order of
statements in a constructor's initialization list, base
classes are initialized before the members of the current
class are.
===
So in query.h:188:
Query(Connection* c, bool te = true) :
std::ostream(&sbuffer_),
OptionalExceptions(te),
Lockable(false),
def(this),
conn_(c),
success_(false)
{
success_ = true;
}
... line: 694
/// \brief String buffer for storing assembled query
std::stringbuf sbuffer_;
===
The std::stringbuf sbuffer_ is not yet initialized when
it is passed into the std::ostream constructor.
If you build with g++, you can get away with this (not
sure if it leads to any memory corruption), but with Sun
Studio 11 compilers (and other compilers), for example,
you will incur a memory access fault.
The simple solution is to make the sbuffer_ member a
pointer and allocate it in Connection::query() passing the
newly created object as a parameter to the Query()
constructor and clean it up in Querys destructor.
Ive attached an example of the changes.
/kristofer
--- ../../../mysql++-2.0.6/lib/connection.cpp Mon Sep 26 10:21:49 2005
+++ connection.cpp Thu Nov 17 13:36:57 2005
@@ -200,7 +200,8 @@
bool
Connection::create_db(const std::string& db)
{
- Query q(this, throw_exceptions());
+ std::stringbuf *sb = new std::stringbuf;
+ Query q(this, sb, throw_exceptions());
return q.exec("CREATE DATABASE " + db);
}
@@ -208,7 +209,8 @@
bool
Connection::drop_db(const std::string& db)
{
- Query q(this, throw_exceptions());
+ std::stringbuf *sb = new std::stringbuf;
+ Query q(this, sb, throw_exceptions());
return q.exec("DROP DATABASE " + db);
}
@@ -272,7 +274,8 @@
Query
Connection::query()
{
- return Query(this, throw_exceptions());
+ std::stringbuf *sb = new std::stringbuf;
+ return Query(this, sb, throw_exceptions());
}
--- ../../../mysql++-2.0.6/lib/query.cpp Mon Sep 26 10:21:49 2005
+++ query.cpp Thu Nov 17 13:32:32 2005
@@ -31,7 +31,7 @@
namespace mysqlpp {
Query::Query(const Query& q) :
-std::ostream(&sbuffer_),
+std::ostream(sbuffer_),
OptionalExceptions(q.exceptions()),
Lockable(q.locked()),
def(q.def),
@@ -291,9 +291,9 @@
char* Query::preview_char()
{
*this << std::ends;
- size_t length = sbuffer_.str().size();
+ size_t length = sbuffer_->str().size();
char* s = new char[length + 1];
- strcpy(s, sbuffer_.str().c_str());
+ strcpy(s, sbuffer_->str().c_str());
return s;
}
@@ -300,7 +300,7 @@
void Query::proc(SQLQueryParms& p)
{
- sbuffer_.str("");
+ sbuffer_->str("");
char num;
SQLString* ss;
@@ -333,7 +333,7 @@
{
seekp(0);
clear();
- sbuffer_.str("");
+ sbuffer_->str("");
parse_elems_.clear();
def.clear();
@@ -452,7 +452,7 @@
*this << std::ends;
- return sbuffer_.str();
+ return sbuffer_->str();
}
--- ../../../mysql++-2.0.6/lib/query.h Thu Nov 17 17:13:51 2005
+++ query.h Thu Nov 17 17:14:08 2005
@@ -185,17 +185,23 @@
///
/// \param c connection the finished query should be sent out on
/// \param te if true, throw exceptions on errors
- Query(Connection* c, bool te = true) :
- std::ostream(&sbuffer_),
+ Query(Connection* c, std::stringbuf *sb, bool te = true) :
+ std::ostream(sb),
OptionalExceptions(te),
Lockable(false),
def(this),
conn_(c),
- success_(false)
+ success_(false),
+ sbuffer_(sb)
{
success_ = true;
}
+ ~Query()
+ {
+ delete sbuffer_;
+ }
+
/// \brief Create a new query object as a copy of another.
///
/// This is \b not a traditional copy ctor! Its only purpose is to
@@ -692,7 +698,7 @@
std::map<std::string, short int> parsed_nums_;
/// \brief String buffer for storing assembled query
- std::stringbuf sbuffer_;
+ std::stringbuf *sbuffer_;
//// Internal support functions
my_ulonglong affected_rows() const;