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

Reply via email to