MySQL++ Reference Manual

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

# 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