query.h

Go to the documentation of this file.
00001 
00002 
00003 
00004 /***********************************************************************
00005  Copyright (c) 1998 by Kevin Atkinson, (c) 1999-2001 by MySQL AB, and
00006  (c) 2004-2011 by Educational Technology Resources, Inc.  Others may
00007  also hold copyrights on code in this file.  See the CREDITS.txt file
00008  in the top directory of the distribution for details.
00009 
00010  This file is part of MySQL++.
00011 
00012  MySQL++ is free software; you can redistribute it and/or modify it
00013  under the terms of the GNU Lesser General Public License as published
00014  by the Free Software Foundation; either version 2.1 of the License, or
00015  (at your option) any later version.
00016 
00017  MySQL++ is distributed in the hope that it will be useful, but WITHOUT
00018  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00019  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00020  License for more details.
00021 
00022  You should have received a copy of the GNU Lesser General Public
00023  License along with MySQL++; if not, write to the Free Software
00024  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
00025  USA
00026 ***********************************************************************/
00027 
00028 #if !defined(MYSQLPP_QUERY_H)
00029 #define MYSQLPP_QUERY_H
00030 
00031 #include "common.h"
00032 
00033 #include "exceptions.h"
00034 #include "noexceptions.h"
00035 #include "qparms.h"
00036 #include "querydef.h"
00037 #include "result.h"
00038 #include "row.h"
00039 #include "sqlstream.h"
00040 #include "stadapter.h"
00041 #include "transaction.h"
00042 
00043 #include <deque>
00044 #include <iomanip>
00045 #include <list>
00046 #include <map>
00047 #include <set>
00048 #include <vector>
00049 
00050 #ifdef HAVE_EXT_SLIST
00051 #  include <ext/slist>
00052 #else
00053 #  if defined(HAVE_STD_SLIST) || defined(HAVE_GLOBAL_SLIST)
00054 #      include <slist>
00055 #  endif
00056 #endif
00057 
00058 namespace mysqlpp {
00059 
00060 #if !defined(DOXYGEN_IGNORE)
00061 // Make Doxygen ignore this
00062 class MYSQLPP_EXPORT Connection;
00063 class MYSQLPP_EXPORT Transaction;
00064 #endif
00065 
00120 
00121 class MYSQLPP_EXPORT Query :
00122                 public std::ostream,
00123                 public OptionalExceptions
00124 {
00125 public:
00126 #if !defined(DOXYGEN_IGNORE)
00127         // Bring in InsertPolicy template as part of this class's interface,
00128         // separate only in the sense that it's a self-contained concept.
00129         #include "insertpolicy.h"
00130 #endif
00131 
00139         Query(Connection* c, bool te = true, const char* qstr = 0);
00140 
00148         Query(const Query& q);
00149 
00151         ulonglong affected_rows();
00152 
00167         size_t escape_string(std::string* ps, const char* original = 0,
00168                         size_t length = 0) const;
00169 
00191         size_t escape_string(char* escaped, const char* original,
00192                         size_t length) const;
00193 
00198         int errnum() const;
00199 
00204         const char* error() const;
00205 
00208         std::string info();
00209 
00220         ulonglong insert_id();
00221 
00226         Query& operator=(const Query& rhs);
00227 
00246         operator void*() const;
00247 
00255         bool operator !() const { return !operator void*(); }
00256 
00264         void parse();
00265 
00275         void reset();
00276 
00280         bool result_empty();
00281 
00283         std::string str() { return str(template_defaults); }
00284 
00298         std::string str(const SQLTypeAdapter& arg0)
00299                         { return str(SQLQueryParms() << arg0); }
00300 
00305         std::string str(SQLQueryParms& p);
00306 
00317         bool exec() { return exec(str(template_defaults)); }
00318 
00330         bool exec(const std::string& str);
00331 
00348         SimpleResult execute(); 
00349 
00358         SimpleResult execute(SQLQueryParms& p);
00359 
00376         SimpleResult execute(const SQLTypeAdapter& str);
00377 
00382         SimpleResult execute(const char* str, size_t len);
00383 
00409         UseQueryResult use();
00410 
00420         UseQueryResult use(SQLQueryParms& p);
00421 
00439         UseQueryResult use(const SQLTypeAdapter& str);
00440 
00450         UseQueryResult use(const char* str, size_t len);
00451 
00473         StoreQueryResult store();
00474 
00483         StoreQueryResult store(SQLQueryParms& p);
00484 
00502         StoreQueryResult store(const SQLTypeAdapter& str);
00503 
00513         StoreQueryResult store(const char* str, size_t len);
00514 
00525         template <typename Function>
00526         Function for_each(const SQLTypeAdapter& query, Function fn)
00527         {       
00528                 mysqlpp::UseQueryResult res = use(query);
00529                 if (res) {
00530                         mysqlpp::NoExceptions ne(res);
00531                         while (mysqlpp::Row row = res.fetch_row()) {
00532                                 fn(row);
00533                         }
00534                 }
00535 
00536                 return fn;
00537         }
00538 
00546         template <typename Function>
00547         Function for_each(Function fn)
00548         {       
00549                 mysqlpp::UseQueryResult res = use();
00550                 if (res) {
00551                         mysqlpp::NoExceptions ne(res);
00552                         while (mysqlpp::Row row = res.fetch_row()) {
00553                                 fn(row);
00554                         }
00555                 }
00556 
00557                 return fn;
00558         }
00559 
00570         template <class SSQLS, typename Function>
00571         Function for_each(const SSQLS& ssqls, Function fn)
00572         {       
00573                 std::string query("select * from `");
00574                 query += ssqls.table();
00575       query += '`';
00576                 mysqlpp::UseQueryResult res = use(query);
00577                 if (res) {
00578                         mysqlpp::NoExceptions ne(res);
00579                         while (mysqlpp::Row row = res.fetch_row()) {
00580                                 fn(row);
00581                         }
00582                 }
00583 
00584                 return fn;
00585         }
00586 
00606         template <class Sequence, typename Function>
00607         Function store_if(Sequence& con, const SQLTypeAdapter& query, Function fn)
00608         {       
00609                 mysqlpp::UseQueryResult res = use(query);
00610                 if (res) {
00611                         mysqlpp::NoExceptions ne(res);
00612                         while (mysqlpp::Row row = res.fetch_row()) {
00613                                 if (fn(row)) {
00614                                         con.push_back(row);
00615                                 }
00616                         }
00617                 }
00618 
00619                 return fn;
00620         }
00621 
00633         template <class Sequence, class SSQLS, typename Function>
00634         Function store_if(Sequence& con, const SSQLS& ssqls, Function fn)
00635         {       
00636                 std::string query("select * from `");
00637                 query += ssqls.table();
00638       query += '`';
00639                 mysqlpp::UseQueryResult res = use(query);
00640                 if (res) {
00641                         mysqlpp::NoExceptions ne(res);
00642                         while (mysqlpp::Row row = res.fetch_row()) {
00643                                 if (fn(row)) {
00644                                         con.push_back(row);
00645                                 }
00646                         }
00647                 }
00648 
00649                 return fn;
00650         }
00651 
00661         template <class Sequence, typename Function>
00662         Function store_if(Sequence& con, Function fn)
00663         {       
00664                 mysqlpp::UseQueryResult res = use();
00665                 if (res) {
00666                         mysqlpp::NoExceptions ne(res);
00667                         while (mysqlpp::Row row = res.fetch_row()) {
00668                                 if (fn(row)) {
00669                                         con.push_back(row);
00670                                 }
00671                         }
00672                 }
00673 
00674                 return fn;
00675         }
00676 
00703         StoreQueryResult store_next();
00704 
00716         bool more_results();
00717 
00734         template <class Sequence>
00735         void storein_sequence(Sequence& con)
00736         {
00737                 storein_sequence(con, str(template_defaults));
00738         }
00739 
00753         template <class Sequence>
00754         void storein_sequence(Sequence& con, const SQLTypeAdapter& s)
00755         {
00756                 if (UseQueryResult result = use(s)) {
00757                         while (1) {
00758                                 MYSQL_ROW d = result.fetch_raw_row();
00759                                 if (!d) break;
00760                                 Row row(d, &result, result.fetch_lengths(),
00761                                                 throw_exceptions());
00762                                 if (!row) break;
00763                                 con.push_back(typename Sequence::value_type(row));
00764                         }
00765                 }
00766                 else if (!result_empty()) {
00767                         // Underlying MySQL C API returned an empty result for this
00768                         // query, but it also says it should have returned
00769                         // something.  Reasons it can do that are given here:
00770                         // http://dev.mysql.com/doc/refman/5.5/en/null-mysql-store-result.html
00771                         // Regardless, it means the C library barfed, so we can't
00772                         // just return an empty result set.
00773                         copacetic_ = false;
00774                         if (throw_exceptions()) {
00775                                 throw UseQueryError("Bogus empty result");
00776                         }
00777                 }
00778                 // else, it was *supposed* to return nothing, because query was
00779                 // an INSERT, CREATE, etc. sort.  So, leave con untouched.
00780         }
00781 
00792         template <class Seq>
00793         void storein_sequence(Seq& con, SQLQueryParms& p)
00794         {
00795                 storein_sequence(con, str(p));
00796         }
00797 
00805         template <class Set>
00806         void storein_set(Set& con)
00807         {
00808                 storein_set(con, str(template_defaults));
00809         }
00810 
00824         template <class Set>
00825         void storein_set(Set& con, const SQLTypeAdapter& s)
00826         {
00827                 if (UseQueryResult result = use(s)) {
00828                         while (1) {
00829                                 MYSQL_ROW d = result.fetch_raw_row();
00830                                 if (!d) break;
00831                                 Row row(d, &result, result.fetch_lengths(),
00832                                                 throw_exceptions());
00833                                 if (!row) break;
00834                                 con.insert(typename Set::value_type(row));
00835                         }
00836                 }
00837                 else if (!result_empty()) {
00838                         // Underlying MySQL C API returned an empty result for this
00839                         // query, but it also says it should have returned
00840                         // something.  Reasons it can do that are given here:
00841                         // http://dev.mysql.com/doc/refman/5.5/en/null-mysql-store-result.html
00842                         // Regardless, it means the C library barfed, so we can't
00843                         // just return an empty result set.
00844                         copacetic_ = false;
00845                         if (throw_exceptions()) {
00846                                 throw UseQueryError("Bogus empty result");
00847                         }
00848                 }
00849                 // else, it was *supposed* to return nothing, because query was
00850                 // an INSERT, CREATE, etc. sort.  So, leave con untouched.
00851         }
00852 
00863         template <class Set>
00864         void storein_set(Set& con, SQLQueryParms& p)
00865         {
00866                 storein_set(con, str(p));
00867         }
00868 
00887         template <class Container>
00888         void storein(Container& con)
00889         {
00890                 storein(con, str(template_defaults));
00891         }
00892 
00899         template <class T>
00900         void storein(T& con, SQLQueryParms& p)
00901         {
00902                 storein(con, str(p));
00903         }
00904 
00906         template <class T>
00907         void storein(std::vector<T>& con, const SQLTypeAdapter& s)
00908         {
00909                 storein_sequence(con, s);
00910         }
00911 
00913         template <class T>
00914         void storein(std::deque<T>& con, const SQLTypeAdapter& s)
00915         {
00916                 storein_sequence(con, s);
00917         }
00918 
00920         template <class T>
00921         void storein(std::list<T>& con, const SQLTypeAdapter& s)
00922         {
00923                 storein_sequence(con, s);
00924         }
00925 
00926 #if defined(HAVE_EXT_SLIST)
00929         template <class T>
00930         void storein(__gnu_cxx::slist<T>& con, const SQLTypeAdapter& s)
00931         {
00932                 storein_sequence(con, s);
00933         }
00934 #elif defined(HAVE_GLOBAL_SLIST)
00941         template <class T>
00942         void storein(slist<T>& con, const SQLTypeAdapter& s)
00943         {
00944                 storein_sequence(con, s);
00945         }
00946 #elif defined(HAVE_STD_SLIST)
00952         template <class T>
00953         void storein(std::slist<T>& con, const SQLTypeAdapter& s)
00954         {
00955                 storein_sequence(con, s);
00956         }
00957 #endif
00958 
00960         template <class T>
00961         void storein(std::set<T>& con, const SQLTypeAdapter& s)
00962         {
00963                 storein_set(con, s);
00964         }
00965 
00967         template <class T>
00968         void storein(std::multiset<T>& con, const SQLTypeAdapter& s)
00969         {
00970                 storein_set(con, s);
00971         }
00972 
00983         template <class T>
00984         Query& update(const T& o, const T& n)
00985         {
00986                 reset();
00987 
00988                 // Cast required for VC++ 2003 due to error in overloaded operator
00989                 // lookup logic.  For an explanation of the problem, see:
00990                 // http://groups-beta.google.com/group/microsoft.public.vc.stl/browse_thread/thread/9a68d84644e64f15
00991                 MYSQLPP_QUERY_THISPTR << std::setprecision(16) <<
00992                                 "UPDATE `" << o.table() << "` SET " << n.equal_list() <<
00993                                 " WHERE " << o.equal_list(" AND ", sql_use_compare);
00994                 return *this;
00995         }
00996 
01005         template <class T>
01006         Query& insert(const T& v)
01007         {
01008                 reset();
01009 
01010                 MYSQLPP_QUERY_THISPTR << std::setprecision(16) <<
01011                                 "INSERT INTO `" << v.table() << "` (" <<
01012                                 v.field_list() << ") VALUES (" <<
01013                                 v.value_list() << ')';
01014                 return *this;
01015         }
01016 
01030         template <class Iter>
01031         Query& insert(Iter first, Iter last)
01032         {
01033                 reset();
01034 
01035                 if (first != last) {
01036                         // Build SQL for first item in the container.  It's special
01037                         // because we need the table name and field list.
01038                         MYSQLPP_QUERY_THISPTR << std::setprecision(16) <<
01039                                         "INSERT INTO `" << first->table() << "` (" <<
01040                                         first->field_list() << ") VALUES (" <<
01041                                         first->value_list() << ')';
01042 
01043                         // Now insert any remaining container elements.  Be careful
01044                         // hacking on the iterator use here: we want it to work
01045                         // with containers providing only a forward iterator.
01046                         Iter it = first;
01047                         while (++it != last) {
01048                                 MYSQLPP_QUERY_THISPTR << ",(" << it->value_list() << ')';
01049                         }
01050                 }
01051 
01052                 return *this;
01053         }
01054 
01067         template <class Iter, class InsertPolicy>
01068         Query& insertfrom(Iter first, Iter last, InsertPolicy& policy)
01069         {
01070                 bool success = true;
01071                 bool empty = true;
01072 
01073                 reset();
01074 
01075                 if (first == last) {
01076                         return *this;   // empty set!
01077                 }
01078 
01079                 typename InsertPolicy::access_controller ac(*conn_);
01080                 
01081                 for (Iter it = first; it != last; ++it) {
01082                         if (policy.can_add(int(tellp()), *it)) {
01083                                 if (empty) {
01084                                         MYSQLPP_QUERY_THISPTR << std::setprecision(16) <<
01085                                                 "INSERT INTO `" << it->table() << "` (" <<
01086                                                 it->field_list() << ") VALUES (";
01087                                 } 
01088                                 else {
01089                                         MYSQLPP_QUERY_THISPTR << ",(";
01090                                 }
01091 
01092                                 MYSQLPP_QUERY_THISPTR << it->value_list() << ')';
01093 
01094                                 empty = false;
01095                         } 
01096                         else {
01097                                 // Execute what we've built up already, if there is anything
01098                                 if (!empty) {
01099                                         if (!exec()) {
01100                                                 success = false;
01101                                                 break;
01102                                         }
01103 
01104                                         empty = true;
01105                                 }
01106 
01107                                 // If we _still_ can't add, the policy is too strict
01108                                 if (policy.can_add(int(tellp()), *it)) {
01109                                         MYSQLPP_QUERY_THISPTR << std::setprecision(16) <<
01110                                                 "INSERT INTO `" << it->table() << "` (" <<
01111                                                 it->field_list() << ") VALUES (" <<
01112                                                 it->value_list() << ')';
01113 
01114                                         empty = false;
01115                                 } 
01116                                 else {
01117                                         // At this point all we can do is give up
01118                                         if (throw_exceptions()) {
01119                                                 throw BadInsertPolicy("Insert policy is too strict");
01120                                         }
01121 
01122                                         success = false;
01123                                         break;
01124                                 }
01125                         }
01126                 }
01127 
01128                 // We might need to execute the last query here.
01129                 if (success && !empty && !exec()) {
01130                         success = false;
01131                 }
01132 
01133                 if (success) {
01134                         ac.commit();
01135                 } 
01136                 else {
01137                         ac.rollback();
01138                 }
01139 
01140                 return *this;
01141         }
01142 
01155         template <class Iter, class InsertPolicy>
01156         Query& replacefrom(Iter first, Iter last, InsertPolicy& policy)
01157         {
01158                 bool success = true;
01159                 bool empty = true;
01160 
01161                 reset();
01162 
01163                 if (first == last) {
01164                         return *this;   // empty set!
01165                 }
01166 
01167                 typename InsertPolicy::access_controller ac(*conn_);
01168 
01169                 for (Iter it = first; it != last; ++it) {
01170                         if (policy.can_add(int(tellp()), *it)) {
01171                                 if (empty) {
01172                                         MYSQLPP_QUERY_THISPTR << std::setprecision(16) <<
01173                                                 "REPLACE INTO `" << it->table() << "` (" <<
01174                                                 it->field_list() << ") VALUES (";
01175                                 }
01176                                 else {
01177                                         MYSQLPP_QUERY_THISPTR << ",(";
01178                                 }
01179 
01180                                 MYSQLPP_QUERY_THISPTR << it->value_list() << ')';
01181 
01182                                 empty = false;
01183                         }
01184                         else {
01185                                 // Execute what we've built up already, if there is anything
01186                                 if (!empty) {
01187                                         if (!exec()) {
01188                                                 success = false;
01189                                                 break;
01190                                         }
01191 
01192                                         empty = true;
01193                                 }
01194 
01195                                 // If we _still_ can't add, the policy is too strict
01196                                 if (policy.can_add(int(tellp()), *it)) {
01197                                         MYSQLPP_QUERY_THISPTR << std::setprecision(16) <<
01198                                                 "REPLACE INTO `" << it->table() << "` (" <<
01199                                                 it->field_list() << ") VALUES (" <<
01200                                                 it->value_list() << ')';
01201 
01202                                         empty = false;
01203                                 }
01204                                 else {
01205                                         // At this point all we can do is give up
01206                                         if (throw_exceptions()) {
01207                                                 throw BadInsertPolicy("Insert policy is too strict");
01208                                         }
01209 
01210                                         success = false;
01211                                         break;
01212                                 }
01213                         }
01214                 }
01215 
01216                 // We might need to execute the last query here.
01217                 if (success && !empty && !exec()) {
01218                         success = false;
01219                 }
01220 
01221                 if (success) {
01222                         ac.commit();
01223                 }
01224                 else {
01225                         ac.rollback();
01226                 }
01227 
01228                 return *this;
01229         }
01230 
01240         template <class T>
01241         Query& replace(const T& v)
01242         {
01243                 reset();
01244 
01245                 MYSQLPP_QUERY_THISPTR << std::setprecision(16) <<
01246                                 "REPLACE INTO `" << v.table() << "` (" <<
01247                                 v.field_list() << ") VALUES (" << v.value_list() << ')';
01248                 return *this;
01249         }
01250 
01265         template <class Iter>
01266         Query& replace(Iter first, Iter last)
01267         {
01268                 reset();
01269                 if (first != last) {
01270                         // Build SQL for first item in the container.  It's special
01271                         // because we need the table name and field list.
01272                         MYSQLPP_QUERY_THISPTR << std::setprecision(16) <<
01273                                         "REPLACE INTO " << first->table() << " (" <<
01274                                         first->field_list() << ") VALUES (" <<
01275                                         first->value_list() << ')';
01276 
01277                         // Now insert any remaining container elements.  Be careful
01278                         // hacking on the iterator use here: we want it to work
01279                         // with containers providing only a forward iterator.
01280                         Iter it = first;
01281                         while (++it != last) {
01282                                 MYSQLPP_QUERY_THISPTR << ",(" << it->value_list() << ')';
01283                         }
01284                 }
01285 
01286                 return *this;
01287         }       
01288 
01289 #if !defined(DOXYGEN_IGNORE)
01290         // Declare the remaining overloads.  These are hidden down here partly
01291         // to keep the above code clear, but also so that we may hide them
01292         // from Doxygen, which gets confused by macro instantiations that look
01293         // like method declarations.
01294         mysql_query_define0(std::string, str)
01295         mysql_query_define0(SimpleResult, execute)
01296         mysql_query_define0(StoreQueryResult, store)
01297         mysql_query_define0(UseQueryResult, use)
01298         mysql_query_define1(storein_sequence)
01299         mysql_query_define1(storein_set)
01300         mysql_query_define1(storein)
01301 #endif // !defined(DOXYGEN_IGNORE)
01302 
01306         SQLQueryParms template_defaults;
01307 
01308 private:
01309         friend class SQLQueryParms;
01310 
01312         Connection* conn_;
01313 
01315         bool copacetic_;
01316 
01318         std::vector<SQLParseElement> parse_elems_;
01319 
01322         std::vector<std::string> parsed_names_;
01323 
01325         std::map<std::string, short int> parsed_nums_;
01326 
01328         std::stringbuf sbuffer_;
01329 
01331         void proc(SQLQueryParms& p);
01332 
01333         SQLTypeAdapter* pprepare(char option, SQLTypeAdapter& S, bool replace = true);
01334 };
01335 
01336 
01340 inline std::ostream& operator <<(std::ostream& os, Query& q)
01341 {
01342         return os << q.str();
01343 }
01344 
01345 
01346 } // end namespace mysqlpp
01347 
01348 #endif // !defined(MYSQLPP_QUERY_H)
01349 

Generated on 10 Dec 2013 for MySQL++ by  doxygen 1.4.7