Author: wyoung
Date: Sat Oct 7 05:22:28 2006
New Revision: 1327
URL: http://svn.gna.org/viewcvs/mysqlpp?rev=1327&view=rev
Log:
- Query::execute(), store() and use() overload call chain now terminates
in a (const char*, size_t) version instead of just one taking const
char*, so you can execute queries with embedded null characters.
- Hijacked the overload taking just a single SQLString from being used
only for template queries to also be useful for simple queries, for
the same reason. It resolves to either a template query call or to
the version described above.
Modified:
trunk/Wishlist
trunk/lib/query.cpp
trunk/lib/query.h
trunk/lib/querydef.pl
Modified: trunk/Wishlist
URL:
http://svn.gna.org/viewcvs/mysqlpp/trunk/Wishlist?rev=1327&r1=1326&r2=1327&view=diff
==============================================================================
--- trunk/Wishlist (original)
+++ trunk/Wishlist Sat Oct 7 05:22:28 2006
@@ -31,30 +31,12 @@
o Fix handling of /usr/local/mysql as base install dir.
- o Currently, all overloads for Query's execute(), store()
- and use() methods eventually call the const char*
- version, which does the actual work of executing the query.
- This rules out query strings with embedded nulls, as you're
- likely to get with BLOB columns. Also, it means MySQL++
- must scan the string for length in a few places. The C API
- isn't limited in this way if you use mysql_real_query(),
- but you need an accurate length value to call it.
-
- Fix by co-opting the first template query version of each
- of these functions, as it takes a single SQLString, which
- contains a length and doesn't care about nulls. Also add
- an overload taking a const char* and a length parameter,
- for cases where the user doesn't want to convert their
- data to a std::string variant. Make the latter the actual
- terminus of the call chain, as it's cheaper to convert from
- SQLString to const char* than the reverse.
-
o ColData doesn't cope with nulls very well, such as storing
BLOB column data. This manifests in things like Row::at()
returning truncated data, because somewhere along the line
a ColData object was created using only a char*; we need to
be able to use a length as well. Update examples/cgi_image
- to use this new mechanism.
+ and examples/load_file to use this new mechanism.
o A BLOB field containing a null will be truncated when using
SSQLS with a std::string member. This is probably related
Modified: trunk/lib/query.cpp
URL:
http://svn.gna.org/viewcvs/mysqlpp/trunk/lib/query.cpp?rev=1327&r1=1326&r2=1327&view=diff
==============================================================================
--- trunk/lib/query.cpp (original)
+++ trunk/lib/query.cpp Sat Oct 7 05:22:28 2006
@@ -75,19 +75,22 @@
}
-my_ulonglong Query::affected_rows() const
+my_ulonglong
+Query::affected_rows() const
{
return conn_->affected_rows();
}
-std::string Query::error()
+std::string
+Query::error()
{
return conn_->error();
}
-bool Query::exec(const std::string& str)
+bool
+Query::exec(const std::string& str)
{
success_ = !mysql_real_query(&conn_->mysql_, str.c_str(),
static_cast<unsigned long>(str.length()));
@@ -100,10 +103,32 @@
}
-ResNSel Query::execute(const char* str)
-{
- success_ = false;
+ResNSel
+Query::execute(const SQLString& str)
+{
+ if (def.size()) {
+ // Take str to be a template query parameter
+ return execute(SQLQueryParms() << str);
+ }
+ else {
+ // Take str to be the entire query string
+ return execute(str.c_str(), str.length());
+ }
+}
+
+
+ResNSel
+Query::execute(const char* str)
+{
+ return execute(SQLString(str));
+}
+
+
+ResNSel
+Query::execute(const char* str, size_t len)
+{
if (lock()) {
+ success_ = false;
if (throw_exceptions()) {
throw LockFailed();
}
@@ -112,18 +137,17 @@
}
}
- success_ = !mysql_query(&conn_->mysql_, str);
+ success_ = !mysql_real_query(&conn_->mysql_, str, len);
+
unlock();
if (success_) {
return ResNSel(conn_);
}
- else {
- if (throw_exceptions()) {
- throw BadQuery(error());
- }
- else {
- return ResNSel();
- }
+ else if (throw_exceptions()) {
+ throw BadQuery(error());
+ }
+ else {
+ return ResNSel();
}
}
@@ -131,34 +155,38 @@
#if !defined(DOXYGEN_IGNORE)
// Doxygen will not generate documentation for this section.
-ResNSel Query::execute(SQLQueryParms& p)
-{
- query_reset r = parse_elems_.size() ? DONT_RESET : RESET_QUERY;
- return execute(str(p, r).c_str());
+ResNSel
+Query::execute(SQLQueryParms& p)
+{
+ return execute(str(p, parse_elems_.size() ? DONT_RESET : RESET_QUERY));
}
#endif // !defined(DOXYGEN_IGNORE)
-std::string Query::info()
+std::string
+Query::info()
{
return conn_->info();
}
-my_ulonglong Query::insert_id()
+my_ulonglong
+Query::insert_id()
{
return conn_->insert_id();
}
-bool Query::lock()
+bool
+Query::lock()
{
return conn_->lock();
}
-bool Query::more_results()
+bool
+Query::more_results()
{
#if MYSQL_VERSION_ID > 41000 // only in MySQL v4.1 +
return mysql_more_results(&conn_->mysql_);
@@ -168,7 +196,8 @@
}
-void Query::parse()
+void
+Query::parse()
{
std::string str = "";
char num[4];
@@ -311,7 +340,8 @@
}
-char* Query::preview_char()
+char*
+Query::preview_char()
{
*this << std::ends;
size_t length = sbuffer_.str().size();
@@ -322,7 +352,8 @@
}
-void Query::proc(SQLQueryParms& p)
+void
+Query::proc(SQLQueryParms& p)
{
sbuffer_.str("");
@@ -330,12 +361,12 @@
i != parse_elems_.end(); ++i) {
dynamic_cast<std::ostream&>(*this) << i->before;
int num = i->num;
- if (num != -1) {
+ if (num >= 0) {
SQLQueryParms* c;
- if (num < p.size()) {
+ if (size_t(num) < p.size()) {
c = &p;
}
- else if (num < def.size()) {
+ else if (size_t(num) < def.size()) {
c = &def;
}
else {
@@ -356,7 +387,8 @@
}
}
-void Query::reset()
+void
+Query::reset()
{
seekp(0);
clear();
@@ -367,11 +399,32 @@
}
-Result Query::store(const char* str)
-{
- success_ = false;
-
+Result
+Query::store(const SQLString& str)
+{
+ if (def.size()) {
+ // Take str to be a template query parameter
+ return store(SQLQueryParms() << str);
+ }
+ else {
+ // Take str to be the entire query string
+ return store(str.c_str(), str.length());
+ }
+}
+
+
+Result
+Query::store(const char* str)
+{
+ return store(SQLString(str));
+}
+
+
+Result
+Query::store(const char* str, size_t len)
+{
if (lock()) {
+ success_ = false;
if (throw_exceptions()) {
throw LockFailed();
}
@@ -380,22 +433,26 @@
}
}
- success_ = !mysql_query(&conn_->mysql_, str);
- if (success_) {
+
+ if (success_ = !mysql_real_query(&conn_->mysql_, str, len)) {
MYSQL_RES* res = mysql_store_result(&conn_->mysql_);
if (res) {
unlock();
return Result(res, throw_exceptions());
}
+ else {
+ success_ = false;
+ }
}
unlock();
- // One of the mysql_* calls failed, so decide how we should fail.
- // Notice that we do not throw an exception if we just get a null
- // result set, but no error. This happens when using store() on a
- // query that may not return results. Obviously it's better to use
- // exec*() in this situation, but it's not outright illegal, and
- // sometimes you have to do it.
+ // One of the MySQL API calls failed, but it's not an error if we
+ // just get an empty result set. It happens when store()ing a query
+ // 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());
}
@@ -408,16 +465,17 @@
#if !defined(DOXYGEN_IGNORE)
// Doxygen will not generate documentation for this section.
-Result Query::store(SQLQueryParms& p)
-{
- query_reset r = parse_elems_.size() ? DONT_RESET : RESET_QUERY;
- return store(str(p, r).c_str());
+Result
+Query::store(SQLQueryParms& p)
+{
+ return store(str(p, parse_elems_.size() ? DONT_RESET : RESET_QUERY));
}
#endif // !defined(DOXYGEN_IGNORE)
-Result Query::store_next()
+Result
+Query::store_next()
{
#if MYSQL_VERSION_ID > 41000 // only in MySQL v4.1 +
if (lock()) {
@@ -471,7 +529,8 @@
}
-std::string Query::str(SQLQueryParms& p)
+std::string
+Query::str(SQLQueryParms& p)
{
if (!parse_elems_.empty()) {
proc(p);
@@ -483,7 +542,8 @@
}
-std::string Query::str(SQLQueryParms& p, query_reset r)
+std::string
+Query::str(SQLQueryParms& p, query_reset r)
{
std::string tmp = str(p);
if (r == RESET_QUERY) {
@@ -493,22 +553,46 @@
}
-bool Query::success()
+bool
+Query::success()
{
return success_ && conn_->success();
}
-void Query::unlock()
+void
+Query::unlock()
{
conn_->unlock();
}
-ResUse Query::use(const char* str)
-{
- success_ = false;
+ResUse
+Query::use(const SQLString& str)
+{
+ if (def.size()) {
+ // Take str to be a template query parameter
+ return use(SQLQueryParms() << str);
+ }
+ else {
+ // Take str to be the entire query string
+ return use(str.c_str(), str.length());
+ }
+}
+
+
+ResUse
+Query::use(const char* str)
+{
+ return use(SQLString(str));
+}
+
+
+ResUse
+Query::use(const char* str, size_t len)
+{
if (lock()) {
+ success_ = false;
if (throw_exceptions()) {
throw LockFailed();
}
@@ -517,8 +601,7 @@
}
}
- success_ = !mysql_query(&conn_->mysql_, str);
- if (success_) {
+ if (success_ = !mysql_real_query(&conn_->mysql_, str, len)) {
MYSQL_RES* res = mysql_use_result(&conn_->mysql_);
if (res) {
unlock();
@@ -527,8 +610,14 @@
}
unlock();
- // One of the mysql_* calls failed, so decide how we should fail.
- if (throw_exceptions()) {
+ // One of the MySQL API calls failed, but it's not an error if we
+ // just get an empty result set. It happens when use()ing a query
+ // 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());
}
else {
@@ -540,10 +629,10 @@
#if !defined(DOXYGEN_IGNORE)
// Doxygen will not generate documentation for this section.
-ResUse Query::use(SQLQueryParms& p)
-{
- query_reset r = parse_elems_.size() ? DONT_RESET : RESET_QUERY;
- return use(str(p, r).c_str());
+ResUse
+Query::use(SQLQueryParms& p)
+{
+ return use(str(p, parse_elems_.size() ? DONT_RESET : RESET_QUERY));
}
#endif // !defined(DOXYGEN_IGNORE)
Modified: trunk/lib/query.h
URL:
http://svn.gna.org/viewcvs/mysqlpp/trunk/lib/query.h?rev=1327&r1=1326&r2=1327&view=diff
==============================================================================
--- trunk/lib/query.h (original)
+++ trunk/lib/query.h Sat Oct 7 05:22:28 2006
@@ -171,26 +171,33 @@
/// \brief Return the query string currently in the buffer.
std::string preview() { return str(def); }
+ /// \brief Return the query string currently in the buffer with
+ /// template query parameter substitution.
+ ///
+ /// \param arg0 the value to substitute for the first template query
+ /// parameter
+ std::string preview(const SQLString& arg0)
+ { return preview(SQLQueryParms() << arg0); }
+
/// \brief Return the query string currently in the buffer.
- std::string preview(SQLQueryParms& p)
- {
- return str(p);
- }
+ std::string preview(SQLQueryParms& p) { return str(p); }
/// \brief Get built query as a null-terminated C++ string
- std::string str()
- {
- return str(def);
- }
+ std::string str() { return str(def); }
+
+ /// \brief Get built query as a null-terminated C++ string with
+ /// template query parameter substitution.
+ ///
+ /// \param arg0 the value to substitute for the first template query
+ /// parameter
+ std::string str(const SQLString& arg0)
+ { return preview(SQLQueryParms() << arg0); }
/// \brief Get built query as a null-terminated C++ string
///
/// \param r if equal to \c RESET_QUERY, query object is cleared
/// after this call
- std::string str(query_reset r)
- {
- return str(def, r);
- }
+ std::string str(query_reset r) { return str(def, r); }
/// \brief Get built query as a null-terminated C++ string
///
@@ -237,10 +244,24 @@
/// \sa exec(), store(), storein(), and use()
ResNSel execute() { return execute(def); }
- /// \brief Execute query in a C++ string
+ /// \brief Execute query in a C++ string, or substitute string into
+ /// a template query and execute it.
+ ///
+ /// \param str If the object represents a compiled template query,
+ /// substitutes this string in for the first parameter. Otherwise,
+ /// takes the string as a complete SQL query and executes it.
+ ResNSel execute(const SQLString& str);
+
+ /// \brief Execute query in a C string
///
/// Executes the query immediately, and returns the results.
ResNSel execute(const char* str);
+
+ /// \brief Execute query in a known-length string of characters.
+ /// This can include null characters.
+ ///
+ /// Executes the query immediately, and returns the results.
+ ResNSel execute(const char* str, size_t len);
/// \brief Execute a query that can return a result set
///
@@ -273,7 +294,21 @@
/// Executes the query immediately, and returns an object that
/// lets you walk through the result set one row at a time, in
/// sequence. This is more memory-efficient than store().
+ ResUse use(const SQLString& str);
+
+ /// \brief Execute query in a C string
+ ///
+ /// Executes the query immediately, and returns an object that
+ /// lets you walk through the result set one row at a time, in
+ /// sequence. This is more memory-efficient than store().
ResUse use(const char* str);
+
+ /// \brief Execute query in a known-length C string
+ ///
+ /// Executes the query immediately, and returns an object that
+ /// lets you walk through the result set one row at a time, in
+ /// sequence. This is more memory-efficient than store().
+ ResUse use(const char* str, size_t len);
/// \brief Execute a query that can return a result set
///
@@ -303,7 +338,21 @@
/// Executes the query immediately, and returns an object that
/// contains the entire result set. This is less memory-efficient
/// than use(), but it lets you have random access to the results.
+ Result store(const SQLString& str);
+
+ /// \brief Execute query in a C string
+ ///
+ /// Executes the query immediately, and returns an object that
+ /// contains the entire result set. This is less memory-efficient
+ /// than use(), but it lets you have random access to the results.
Result store(const char* str);
+
+ /// \brief Execute query in a known-length C string
+ ///
+ /// Executes the query immediately, and returns an object that
+ /// contains the entire result set. This is less memory-efficient
+ /// than use(), but it lets you have random access to the results.
+ Result store(const char* str, size_t len);
/// \brief Return next result set, when processing a multi-query
///
Modified: trunk/lib/querydef.pl
URL:
http://svn.gna.org/viewcvs/mysqlpp/trunk/lib/querydef.pl?rev=1327&r1=1326&r2=1327&view=diff
==============================================================================
--- trunk/lib/querydef.pl (original)
+++ trunk/lib/querydef.pl Sat Oct 7 05:22:28 2006
@@ -55,7 +55,7 @@
## Build mysql_query_define0 macro
print OUT "#define mysql_query_define0(RETURN, FUNC) \\\n";
-for (my $i = 0; $i < $max_parameters; ++$i) {
+for (my $i = 1; $i < $max_parameters; ++$i) {
print OUT "\tRETURN FUNC(";
for (my $j = 0; $j < $i + 1; ++$j) {
print OUT 'const SQLString& arg', $j;
_______________________________________________
Mysqlpp-commits mailing list
[email protected]
https://mail.gna.org/listinfo/mysqlpp-commits