MySQL++: query.h Source File
query.h
Go to the documentation of this file.
/***********************************************************************
Copyright (c) 1998 by Kevin Atkinson, (c) 1999-2001 by MySQL AB, and
(c) 2004-2011 by Educational Technology Resources, Inc. Others may
also hold copyrights on code in this file. See the CREDITS.txt file
in the top directory of the distribution for details.
This file is part of MySQL++.
MySQL++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
MySQL++ is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public
License along with MySQL++; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
USA
***********************************************************************/
#if !defined(MYSQLPP_QUERY_H)
#define MYSQLPP_QUERY_H
#include "common.h"
#include "exceptions.h"
#include "noexceptions.h"
#include "qparms.h"
#include "querydef.h"
#include "result.h"
#include "row.h"
#include "sqlstream.h"
#include "stadapter.h"
#include "transaction.h"
#include <deque>
#include <iomanip>
#include <list>
#include <map>
#include <set>
#include <vector>
#ifdef HAVE_EXT_SLIST
# include <ext/slist>
#else
# if defined(HAVE_STD_SLIST) || defined(HAVE_GLOBAL_SLIST)
# include <slist>
# endif
#endif
namespace mysqlpp {
#if !defined(DOXYGEN_IGNORE)
// Make Doxygen ignore this
class MYSQLPP_EXPORT Connection;
class MYSQLPP_EXPORT Transaction;
#endif
class MYSQLPP_EXPORT Query :
public std::ostream,
public OptionalExceptions
{
public:
// Bring in InsertPolicy template as part of this class's interface,
// separate only in the sense that it's a self-contained concept.
#define MYSQLPP_DEFINE_INSERT_POLICY_TEMPLATES
#include "insertpolicy.h"
#undef MYSQLPP_DEFINE_INSERT_POLICY_TEMPLATES
Query(Connection* c, bool te = true, const char* qstr = 0);
Query(const Query& q);
ulonglong affected_rows();
size_t escape_string(std::string* ps, const char* original = 0,
size_t length = 0) const;
size_t escape_string(char* escaped, const char* original,
size_t length) const;
int errnum() const;
const char* error() const;
std::string info();
ulonglong insert_id();
Query& operator=(const Query& rhs);
operator void*() const;
bool operator !() const { return !operator void*(); }
void parse();
void reset();
bool result_empty();
std::string str() { return str(template_defaults); }
std::string str(const SQLTypeAdapter& arg0)
{ return str(SQLQueryParms() << arg0); }
std::string str(SQLQueryParms& p);
bool exec() { return exec(str(template_defaults)); }
bool exec(const std::string& str);
SimpleResult execute();
SimpleResult execute(SQLQueryParms& p);
SimpleResult execute(const SQLTypeAdapter& str);
SimpleResult execute(const char* str, size_t len);
UseQueryResult use();
UseQueryResult use(SQLQueryParms& p);
UseQueryResult use(const SQLTypeAdapter& str);
UseQueryResult use(const char* str, size_t len);
StoreQueryResult store();
StoreQueryResult store(SQLQueryParms& p);
StoreQueryResult store(const SQLTypeAdapter& str);
StoreQueryResult store(const char* str, size_t len);
template <typename Function>
Function for_each(const SQLTypeAdapter& query, Function fn)
{
mysqlpp::UseQueryResult res = use(query);
if (res) {
mysqlpp::NoExceptions ne(res);
while (mysqlpp::Row row = res.fetch_row()) {
fn(row);
}
}
return fn;
}
template <typename Function>
Function for_each(Function fn)
{
mysqlpp::UseQueryResult res = use();
if (res) {
mysqlpp::NoExceptions ne(res);
while (mysqlpp::Row row = res.fetch_row()) {
fn(row);
}
}
return fn;
}
template <class SSQLS, typename Function>
Function for_each(const SSQLS& ssqls, Function fn)
{
std::string query("select * from `");
query += ssqls.table();
query += '`';
mysqlpp::UseQueryResult res = use(query);
if (res) {
mysqlpp::NoExceptions ne(res);
while (mysqlpp::Row row = res.fetch_row()) {
fn(row);
}
}
return fn;
}
template <class Sequence, typename Function>
Function store_if(Sequence& con, const SQLTypeAdapter& query, Function fn)
{
mysqlpp::UseQueryResult res = use(query);
if (res) {
mysqlpp::NoExceptions ne(res);
while (mysqlpp::Row row = res.fetch_row()) {
if (fn(row)) {
con.push_back(row);
}
}
}
return fn;
}
template <class Sequence, class SSQLS, typename Function>
Function store_if(Sequence& con, const SSQLS& ssqls, Function fn)
{
std::string query("select * from `");
query += ssqls.table();
query += '`';
mysqlpp::UseQueryResult res = use(query);
if (res) {
mysqlpp::NoExceptions ne(res);
while (mysqlpp::Row row = res.fetch_row()) {
if (fn(row)) {
con.push_back(row);
}
}
}
return fn;
}
template <class Sequence, typename Function>
Function store_if(Sequence& con, Function fn)
{
mysqlpp::UseQueryResult res = use();
if (res) {
mysqlpp::NoExceptions ne(res);
while (mysqlpp::Row row = res.fetch_row()) {
if (fn(row)) {
con.push_back(row);
}
}
}
return fn;
}
StoreQueryResult store_next();
bool more_results();
template <class Sequence>
void storein_sequence(Sequence& con)
{
storein_sequence(con, str(template_defaults));
}
template <class Sequence>
void storein_sequence(Sequence& con, const SQLTypeAdapter& s)
{
if (UseQueryResult result = use(s)) {
while (1) {
MYSQL_ROW d = result.fetch_raw_row();
if (!d) break;
Row row(d, &result, result.fetch_lengths(),
throw_exceptions());
if (!row) break;
con.push_back(typename Sequence::value_type(row));
}
}
else if (!result_empty()) {
// Underlying MySQL C API returned an empty result for this
// query, but it also says it should have returned
// something. Reasons it can do that are given here:
// http://dev.mysql.com/doc/refman/5.5/en/null-mysql-store-result.html
// Regardless, it means the C library barfed, so we can't
// just return an empty result set.
copacetic_ = false;
if (throw_exceptions()) {
throw UseQueryError("Bogus empty result");
}
}
// else, it was *supposed* to return nothing, because query was
// an INSERT, CREATE, etc. sort. So, leave con untouched.
}
template <class Seq>
void storein_sequence(Seq& con, SQLQueryParms& p)
{
storein_sequence(con, str(p));
}
template <class Set>
void storein_set(Set& con)
{
storein_set(con, str(template_defaults));
}
template <class Set>
void storein_set(Set& con, const SQLTypeAdapter& s)
{
if (UseQueryResult result = use(s)) {
while (1) {
MYSQL_ROW d = result.fetch_raw_row();
if (!d) break;
Row row(d, &result, result.fetch_lengths(),
throw_exceptions());
if (!row) break;
con.insert(typename Set::value_type(row));
}
}
else if (!result_empty()) {
// Underlying MySQL C API returned an empty result for this
// query, but it also says it should have returned
// something. Reasons it can do that are given here:
// http://dev.mysql.com/doc/refman/5.5/en/null-mysql-store-result.html
// Regardless, it means the C library barfed, so we can't
// just return an empty result set.
copacetic_ = false;
if (throw_exceptions()) {
throw UseQueryError("Bogus empty result");
}
}
// else, it was *supposed* to return nothing, because query was
// an INSERT, CREATE, etc. sort. So, leave con untouched.
}
template <class Set>
void storein_set(Set& con, SQLQueryParms& p)
{
storein_set(con, str(p));
}
template <class Container>
void storein(Container& con)
{
storein(con, str(template_defaults));
}
template <class T>
void storein(T& con, SQLQueryParms& p)
{
storein(con, str(p));
}
template <class T>
void storein(std::vector<T>& con, const SQLTypeAdapter& s)
{
storein_sequence(con, s);
}
template <class T>
void storein(std::deque<T>& con, const SQLTypeAdapter& s)
{
storein_sequence(con, s);
}
template <class T>
void storein(std::list<T>& con, const SQLTypeAdapter& s)
{
storein_sequence(con, s);
}
#if defined(HAVE_EXT_SLIST)
template <class T>
void storein(__gnu_cxx::slist<T>& con, const SQLTypeAdapter& s)
{
storein_sequence(con, s);
}
#elif defined(HAVE_GLOBAL_SLIST)
template <class T>
void storein(slist<T>& con, const SQLTypeAdapter& s)
{
storein_sequence(con, s);
}
#elif defined(HAVE_STD_SLIST)
template <class T>
void storein(std::slist<T>& con, const SQLTypeAdapter& s)
{
storein_sequence(con, s);
}
#endif
template <class T>
void storein(std::set<T>& con, const SQLTypeAdapter& s)
{
storein_set(con, s);
}
template <class T>
void storein(std::multiset<T>& con, const SQLTypeAdapter& s)
{
storein_set(con, s);
}
template <class T>
Query& update(const T& o, const T& n)
{
reset();
// Cast required for VC++ 2003 due to error in overloaded operator
// lookup logic. For an explanation of the problem, see:
// http://groups-beta.google.com/group/microsoft.public.vc.stl/browse_thread/thread/9a68d84644e64f15
MYSQLPP_QUERY_THISPTR << std::setprecision(16) <<
"UPDATE `" << o.table() << "` SET " << n.equal_list() <<
" WHERE " << o.equal_list(" AND ", sql_use_compare);
return *this;
}
template <class T>
Query& insert(const T& v)
{
reset();
MYSQLPP_QUERY_THISPTR << std::setprecision(16) <<
"INSERT INTO `" << v.table() << "` (" <<
v.field_list() << ") VALUES (" <<
v.value_list() << ')';
return *this;
}
template <class Iter>
Query& insert(Iter first, Iter last)
{
reset();
if (first != last) {
// Build SQL for first item in the container. It's special
// because we need the table name and field list.
MYSQLPP_QUERY_THISPTR << std::setprecision(16) <<
"INSERT INTO `" << first->table() << "` (" <<
first->field_list() << ") VALUES (" <<
first->value_list() << ')';
// Now insert any remaining container elements. Be careful
// hacking on the iterator use here: we want it to work
// with containers providing only a forward iterator.
Iter it = first;
while (++it != last) {
MYSQLPP_QUERY_THISPTR << ",(" << it->value_list() << ')';
}
}
return *this;
}
template <class Iter, class InsertPolicy>
Query& insertfrom(Iter first, Iter last, InsertPolicy& policy)
{
bool success = true;
bool empty = true;
reset();
if (first == last) {
return *this; // empty set!
}
typename InsertPolicy::access_controller ac(*conn_);
for (Iter it = first; it != last; ++it) {
if (policy.can_add(int(tellp()), *it)) {
if (empty) {
MYSQLPP_QUERY_THISPTR << std::setprecision(16) <<
"INSERT INTO `" << it->table() << "` (" <<
it->field_list() << ") VALUES (";
}
else {
MYSQLPP_QUERY_THISPTR << ",(";
}
MYSQLPP_QUERY_THISPTR << it->value_list() << ')';
empty = false;
}
else {
// Execute what we've built up already, if there is anything
if (!empty) {
if (!exec()) {
success = false;
break;
}
empty = true;
}
// If we _still_ can't add, the policy is too strict
if (policy.can_add(int(tellp()), *it)) {
MYSQLPP_QUERY_THISPTR << std::setprecision(16) <<
"INSERT INTO `" << it->table() << "` (" <<
it->field_list() << ") VALUES (" <<
it->value_list() << ')';
empty = false;
}
else {
// At this point all we can do is give up
if (throw_exceptions()) {
throw BadInsertPolicy("Insert policy is too strict");
}
success = false;
break;
}
}
}
// We might need to execute the last query here.
if (success && !empty && !exec()) {
success = false;
}
if (success) {
ac.commit();
}
else {
ac.rollback();
}
return *this;
}
template <class Iter, class InsertPolicy>
Query& replacefrom(Iter first, Iter last, InsertPolicy& policy)
{
bool success = true;
bool empty = true;
reset();
if (first == last) {
return *this; // empty set!
}
typename InsertPolicy::access_controller ac(*conn_);
for (Iter it = first; it != last; ++it) {
if (policy.can_add(int(tellp()), *it)) {
if (empty) {
MYSQLPP_QUERY_THISPTR << std::setprecision(16) <<
"REPLACE INTO `" << it->table() << "` (" <<
it->field_list() << ") VALUES (";
}
else {
MYSQLPP_QUERY_THISPTR << ",(";
}
MYSQLPP_QUERY_THISPTR << it->value_list() << ')';
empty = false;
}
else {
// Execute what we've built up already, if there is anything
if (!empty) {
if (!exec()) {
success = false;
break;
}
empty = true;
}
// If we _still_ can't add, the policy is too strict
if (policy.can_add(int(tellp()), *it)) {
MYSQLPP_QUERY_THISPTR << std::setprecision(16) <<
"REPLACE INTO `" << it->table() << "` (" <<
it->field_list() << ") VALUES (" <<
it->value_list() << ')';
empty = false;
}
else {
// At this point all we can do is give up
if (throw_exceptions()) {
throw BadInsertPolicy("Insert policy is too strict");
}
success = false;
break;
}
}
}
// We might need to execute the last query here.
if (success && !empty && !exec()) {
success = false;
}
if (success) {
ac.commit();
}
else {
ac.rollback();
}
return *this;
}
template <class T>
Query& replace(const T& v)
{
reset();
MYSQLPP_QUERY_THISPTR << std::setprecision(16) <<
"REPLACE INTO `" << v.table() << "` (" <<
v.field_list() << ") VALUES (" << v.value_list() << ')';
return *this;
}
template <class Iter>
Query& replace(Iter first, Iter last)
{
reset();
if (first != last) {
// Build SQL for first item in the container. It's special
// because we need the table name and field list.
MYSQLPP_QUERY_THISPTR << std::setprecision(16) <<
"REPLACE INTO " << first->table() << " (" <<
first->field_list() << ") VALUES (" <<
first->value_list() << ')';
// Now insert any remaining container elements. Be careful
// hacking on the iterator use here: we want it to work
// with containers providing only a forward iterator.
Iter it = first;
while (++it != last) {
MYSQLPP_QUERY_THISPTR << ",(" << it->value_list() << ')';
}
}
return *this;
}
#if !defined(DOXYGEN_IGNORE)
// Declare the remaining overloads. These are hidden down here partly
// to keep the above code clear, but also so that we may hide them
// from Doxygen, which gets confused by macro instantiations that look
// like method declarations.
mysql_query_define0(std::string, str)
mysql_query_define0(SimpleResult, execute)
mysql_query_define0(StoreQueryResult, store)
mysql_query_define0(UseQueryResult, use)
mysql_query_define1(storein_sequence)
mysql_query_define1(storein_set)
mysql_query_define1(storein)
#endif // !defined(DOXYGEN_IGNORE)
SQLQueryParms template_defaults;
private:
friend class SQLQueryParms;
Connection* conn_;
bool copacetic_;
std::vector<SQLParseElement> parse_elems_;
std::vector<std::string> parsed_names_;
std::map<std::string, short int> parsed_nums_;
std::stringbuf sbuffer_;
void proc(SQLQueryParms& p);
SQLTypeAdapter* pprepare(char option, SQLTypeAdapter& S, bool replace = true);
};
inline std::ostream& operator <<(std::ostream& os, Query& q)
{
return os << q.str();
}
} // end namespace mysqlpp
#endif // !defined(MYSQLPP_QUERY_H)
mysqlpp::StoreQueryResult
StoreQueryResult set type for "store" queries.
Definition: result.h:209
stadapter.h
Declares the SQLTypeAdapter class.
mysqlpp::Set
A special std::set derivative for holding MySQL data sets.
Definition: myset.h:71
mysqlpp::Query::storein
void storein(std::deque< T > &con, const SQLTypeAdapter &s)
Specialization of storein_sequence() for std::deque.
Definition: query.h:914
qparms.h
Declares the template query parameter-related stuff.
mysqlpp::Query::str
std::string str()
Get built query as a C++ string.
Definition: query.h:283
mysqlpp::Query::store_if
Function store_if(Sequence &con, const SSQLS &ssqls, Function fn)
Pulls every row in a table, conditionally storing each one in a container.
Definition: query.h:634
mysqlpp::Query::storein
void storein(std::multiset< T > &con, const SQLTypeAdapter &s)
Specialization of storein_set() for std::multiset.
Definition: query.h:968
mysqlpp::Query::storein
void storein(std::list< T > &con, const SQLTypeAdapter &s)
Specialization of storein_sequence() for std::list.
Definition: query.h:921
mysqlpp::Query::storein
void storein(std::set< T > &con, const SQLTypeAdapter &s)
Specialization of storein_set() for std::set.
Definition: query.h:961
insertpolicy.h
Declares the InsertPolicy classes.
mysqlpp::Query::for_each
Function for_each(const SQLTypeAdapter &query, Function fn)
Execute a query, and call a functor for each returned row.
Definition: query.h:526
mysqlpp::SimpleResult
Holds information about the result of queries that don't return rows.
Definition: result.h:48
mysqlpp::Query::for_each
Function for_each(Function fn)
Execute the query, and call a functor for each returned row.
Definition: query.h:547
mysqlpp::Connection
Manages the connection to the database server.
Definition: connection.h:59
mysqlpp::Query::storein_set
void storein_set(Set &con)
Execute a query, storing the result set in an STL associative container.
Definition: query.h:806
sqlstream.h
Defines a class for building quoted and escaped SQL text.
mysqlpp::UseQueryResult
StoreQueryResult set type for "use" queries.
Definition: result.h:298
mysqlpp::Query::insertfrom
Query & insertfrom(Iter first, Iter last, InsertPolicy &policy)
Insert multiple new rows using an insert policy to control how the INSERT statements are created usin...
Definition: query.h:1068
mysqlpp::Query::store_if
Function store_if(Sequence &con, Function fn)
Execute the query, conditionally storing each row in a container.
Definition: query.h:662
result.h
Declares classes for holding information about SQL query results.
mysqlpp::NoExceptions
Disable exceptions in an object derived from OptionalExceptions.
Definition: noexceptions.h:119
mysqlpp::Query::str
std::string str(const SQLTypeAdapter &arg0)
Get built query as a C++ string with template query parameter substitution.
Definition: query.h:298
mysqlpp::Query::storein
void storein(std::vector< T > &con, const SQLTypeAdapter &s)
Specialization of storein_sequence() for std::vector.
Definition: query.h:907
mysqlpp::Query::storein_set
void storein_set(Set &con, const SQLTypeAdapter &s)
Executes a query, storing the result rows in an STL set-associative container.
Definition: query.h:825
mysqlpp::Query::storein_sequence
void storein_sequence(Sequence &con, const SQLTypeAdapter &s)
Executes a query, storing the result rows in an STL sequence container.
Definition: query.h:754
mysqlpp::Query::storein_sequence
void storein_sequence(Sequence &con)
Execute a query, storing the result set in an STL sequence container.
Definition: query.h:735
mysqlpp::Query::storein
void storein(T &con, SQLQueryParms &p)
Store template query results into a container.
Definition: query.h:900
mysqlpp::Row
Manages rows from a result set.
Definition: row.h:63
exceptions.h
Declares the MySQL++-specific exception classes.
mysqlpp::Query::replace
Query & replace(const T &v)
Insert new row unless there is an existing row that matches on a unique index, in which case we repla...
Definition: query.h:1241
mysqlpp::OptionalExceptions
Interface allowing a class to have optional exceptions.
Definition: noexceptions.h:71
mysqlpp::Query::exec
bool exec()
Execute a built-up query.
Definition: query.h:317
mysqlpp::Query::for_each
Function for_each(const SSQLS &ssqls, Function fn)
Run a functor for every row in a table.
Definition: query.h:571
mysqlpp::UseQueryResult::fetch_row
Row fetch_row() const
Returns the next row in a "use" query's result set.
Definition: result.cpp:166
mysqlpp::Query::store_if
Function store_if(Sequence &con, const SQLTypeAdapter &query, Function fn)
Execute a query, conditionally storing each row in a container.
Definition: query.h:607
mysqlpp::Query::replacefrom
Query & replacefrom(Iter first, Iter last, InsertPolicy &policy)
Replace multiple new rows using an insert policy to control how the REPLACE statements are created us...
Definition: query.h:1156
mysqlpp::Query::storein_set
void storein_set(Set &con, SQLQueryParms &p)
Execute template query using given parameters, storing the results in a set type container.
Definition: query.h:864
mysqlpp::Query::template_defaults
SQLQueryParms template_defaults
The default template parameters.
Definition: query.h:1306
mysqlpp::BadInsertPolicy
Exception thrown when an insert policy is too strict to create a valid INSERT statement.
Definition: exceptions.h:456
mysqlpp::Query::insert
Query & insert(Iter first, Iter last)
Insert multiple new rows.
Definition: query.h:1031
mysqlpp::Query::operator !
bool operator !() const
Returns true if the query object is not in a bad state.
Definition: query.h:255
mysqlpp::Query::replace
Query & replace(Iter first, Iter last)
Insert multiple new rows, or replace existing ones if there are existing rows that match on key field...
Definition: query.h:1266
mysqlpp::Query::storein
void storein(Container &con)
Execute a query, and store the entire result set in an STL container.
Definition: query.h:888
mysqlpp::Query::update
Query & update(const T &o, const T &n)
Replace an existing row's data with new data.
Definition: query.h:984
row.h
Declares the classes for holding row data from a result set.
common.h
This file includes top-level definitions for use both internal to the library, and outside it....
mysqlpp::Query::insert
Query & insert(const T &v)
Insert a new row.
Definition: query.h:1006
mysqlpp::SQLQueryParms
This class holds the parameter values for filling template queries.
Definition: qparms.h:48
mysqlpp::UseQueryError
Exception thrown when something goes wrong in processing a "use" query.
Definition: exceptions.h:254
mysqlpp::SQLTypeAdapter
Converts many different data types to strings suitable for use in SQL queries.
Definition: stadapter.h:73
mysqlpp::Query::storein_sequence
void storein_sequence(Seq &con, SQLQueryParms &p)
Execute template query using given parameters, storing the results in a sequence type container.
Definition: query.h:793
mysqlpp::Query
A class for building and executing SQL queries.
Definition: query.h:121
transaction.h
Declares the Transaction class.
noexceptions.h
Declares interface that allows exceptions to be optional.