MySQL++  3.3.0
query.h
Go to the documentation of this file.
1 
4 /***********************************************************************
5  Copyright (c) 1998 by Kevin Atkinson, (c) 1999-2001 by MySQL AB, and
6  (c) 2004-2011 by Educational Technology Resources, Inc. Others may
7  also hold copyrights on code in this file. See the CREDITS.txt file
8  in the top directory of the distribution for details.
9 
10  This file is part of MySQL++.
11 
12  MySQL++ is free software; you can redistribute it and/or modify it
13  under the terms of the GNU Lesser General Public License as published
14  by the Free Software Foundation; either version 2.1 of the License, or
15  (at your option) any later version.
16 
17  MySQL++ is distributed in the hope that it will be useful, but WITHOUT
18  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
20  License for more details.
21 
22  You should have received a copy of the GNU Lesser General Public
23  License along with MySQL++; if not, write to the Free Software
24  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
25  USA
26 ***********************************************************************/
27 
28 #if !defined(MYSQLPP_QUERY_H)
29 #define MYSQLPP_QUERY_H
30 
31 #include "common.h"
32 
33 #include "exceptions.h"
34 #include "noexceptions.h"
35 #include "qparms.h"
36 #include "querydef.h"
37 #include "result.h"
38 #include "row.h"
39 #include "sqlstream.h"
40 #include "stadapter.h"
41 #include "transaction.h"
42 
43 #include <deque>
44 #include <iomanip>
45 #include <list>
46 #include <map>
47 #include <set>
48 #include <vector>
49 
50 #ifdef HAVE_EXT_SLIST
51 # include <ext/slist>
52 #else
53 # if defined(HAVE_STD_SLIST) || defined(HAVE_GLOBAL_SLIST)
54 # include <slist>
55 # endif
56 #endif
57 
58 namespace mysqlpp {
59 
60 #if !defined(DOXYGEN_IGNORE)
61 // Make Doxygen ignore this
62 class MYSQLPP_EXPORT Connection;
63 class MYSQLPP_EXPORT Transaction;
64 #endif
65 
120 
121 class MYSQLPP_EXPORT Query :
122  public std::ostream,
123  public OptionalExceptions
124 {
125 public:
126  // Bring in InsertPolicy template as part of this class's interface,
127  // separate only in the sense that it's a self-contained concept.
128  #define MYSQLPP_DEFINE_INSERT_POLICY_TEMPLATES
129  #include "insertpolicy.h"
130  #undef MYSQLPP_DEFINE_INSERT_POLICY_TEMPLATES
131 
139  Query(Connection* c, bool te = true, const char* qstr = 0);
140 
148  Query(const Query& q);
149 
151  ulonglong affected_rows();
152 
167  size_t escape_string(std::string* ps, const char* original = 0,
168  size_t length = 0) const;
169 
191  size_t escape_string(char* escaped, const char* original,
192  size_t length) const;
193 
198  int errnum() const;
199 
204  const char* error() const;
205 
208  std::string info();
209 
220  ulonglong insert_id();
221 
226  Query& operator=(const Query& rhs);
227 
246  operator void*() const;
247 
255  bool operator !() const { return !operator void*(); }
256 
264  void parse();
265 
275  void reset();
276 
280  bool result_empty();
281 
283  std::string str() { return str(template_defaults); }
284 
298  std::string str(const SQLTypeAdapter& arg0)
299  { return str(SQLQueryParms() << arg0); }
300 
305  std::string str(SQLQueryParms& p);
306 
317  bool exec() { return exec(str(template_defaults)); }
318 
330  bool exec(const std::string& str);
331 
348  SimpleResult execute();
349 
358  SimpleResult execute(SQLQueryParms& p);
359 
376  SimpleResult execute(const SQLTypeAdapter& str);
377 
382  SimpleResult execute(const char* str, size_t len);
383 
409  UseQueryResult use();
410 
421 
439  UseQueryResult use(const SQLTypeAdapter& str);
440 
450  UseQueryResult use(const char* str, size_t len);
451 
473  StoreQueryResult store();
474 
484 
502  StoreQueryResult store(const SQLTypeAdapter& str);
503 
513  StoreQueryResult store(const char* str, size_t len);
514 
525  template <typename Function>
526  Function for_each(const SQLTypeAdapter& query, Function fn)
527  {
528  mysqlpp::UseQueryResult res = use(query);
529  if (res) {
530  mysqlpp::NoExceptions ne(res);
531  while (mysqlpp::Row row = res.fetch_row()) {
532  fn(row);
533  }
534  }
535 
536  return fn;
537  }
538 
546  template <typename Function>
547  Function for_each(Function fn)
548  {
549  mysqlpp::UseQueryResult res = use();
550  if (res) {
551  mysqlpp::NoExceptions ne(res);
552  while (mysqlpp::Row row = res.fetch_row()) {
553  fn(row);
554  }
555  }
556 
557  return fn;
558  }
559 
570  template <class SSQLS, typename Function>
571  Function for_each(const SSQLS& ssqls, Function fn)
572  {
573  std::string query("select * from `");
574  query += ssqls.table();
575  query += '`';
576  mysqlpp::UseQueryResult res = use(query);
577  if (res) {
578  mysqlpp::NoExceptions ne(res);
579  while (mysqlpp::Row row = res.fetch_row()) {
580  fn(row);
581  }
582  }
583 
584  return fn;
585  }
586 
606  template <class Sequence, typename Function>
607  Function store_if(Sequence& con, const SQLTypeAdapter& query, Function fn)
608  {
609  mysqlpp::UseQueryResult res = use(query);
610  if (res) {
611  mysqlpp::NoExceptions ne(res);
612  while (mysqlpp::Row row = res.fetch_row()) {
613  if (fn(row)) {
614  con.push_back(row);
615  }
616  }
617  }
618 
619  return fn;
620  }
621 
633  template <class Sequence, class SSQLS, typename Function>
634  Function store_if(Sequence& con, const SSQLS& ssqls, Function fn)
635  {
636  std::string query("select * from `");
637  query += ssqls.table();
638  query += '`';
639  mysqlpp::UseQueryResult res = use(query);
640  if (res) {
641  mysqlpp::NoExceptions ne(res);
642  while (mysqlpp::Row row = res.fetch_row()) {
643  if (fn(row)) {
644  con.push_back(row);
645  }
646  }
647  }
648 
649  return fn;
650  }
651 
661  template <class Sequence, typename Function>
662  Function store_if(Sequence& con, Function fn)
663  {
664  mysqlpp::UseQueryResult res = use();
665  if (res) {
666  mysqlpp::NoExceptions ne(res);
667  while (mysqlpp::Row row = res.fetch_row()) {
668  if (fn(row)) {
669  con.push_back(row);
670  }
671  }
672  }
673 
674  return fn;
675  }
676 
703  StoreQueryResult store_next();
704 
716  bool more_results();
717 
734  template <class Sequence>
735  void storein_sequence(Sequence& con)
736  {
737  storein_sequence(con, str(template_defaults));
738  }
739 
753  template <class Sequence>
754  void storein_sequence(Sequence& con, const SQLTypeAdapter& s)
755  {
756  if (UseQueryResult result = use(s)) {
757  while (1) {
758  MYSQL_ROW d = result.fetch_raw_row();
759  if (!d) break;
760  Row row(d, &result, result.fetch_lengths(),
761  throw_exceptions());
762  if (!row) break;
763  con.push_back(typename Sequence::value_type(row));
764  }
765  }
766  else if (!result_empty()) {
767  // Underlying MySQL C API returned an empty result for this
768  // query, but it also says it should have returned
769  // something. Reasons it can do that are given here:
770  // http://dev.mysql.com/doc/refman/5.5/en/null-mysql-store-result.html
771  // Regardless, it means the C library barfed, so we can't
772  // just return an empty result set.
773  copacetic_ = false;
774  if (throw_exceptions()) {
775  throw UseQueryError("Bogus empty result");
776  }
777  }
778  // else, it was *supposed* to return nothing, because query was
779  // an INSERT, CREATE, etc. sort. So, leave con untouched.
780  }
781 
792  template <class Seq>
793  void storein_sequence(Seq& con, SQLQueryParms& p)
794  {
795  storein_sequence(con, str(p));
796  }
797 
805  template <class Set>
806  void storein_set(Set& con)
807  {
808  storein_set(con, str(template_defaults));
809  }
810 
824  template <class Set>
825  void storein_set(Set& con, const SQLTypeAdapter& s)
826  {
827  if (UseQueryResult result = use(s)) {
828  while (1) {
829  MYSQL_ROW d = result.fetch_raw_row();
830  if (!d) break;
831  Row row(d, &result, result.fetch_lengths(),
832  throw_exceptions());
833  if (!row) break;
834  con.insert(typename Set::value_type(row));
835  }
836  }
837  else if (!result_empty()) {
838  // Underlying MySQL C API returned an empty result for this
839  // query, but it also says it should have returned
840  // something. Reasons it can do that are given here:
841  // http://dev.mysql.com/doc/refman/5.5/en/null-mysql-store-result.html
842  // Regardless, it means the C library barfed, so we can't
843  // just return an empty result set.
844  copacetic_ = false;
845  if (throw_exceptions()) {
846  throw UseQueryError("Bogus empty result");
847  }
848  }
849  // else, it was *supposed* to return nothing, because query was
850  // an INSERT, CREATE, etc. sort. So, leave con untouched.
851  }
852 
863  template <class Set>
865  {
866  storein_set(con, str(p));
867  }
868 
887  template <class Container>
888  void storein(Container& con)
889  {
890  storein(con, str(template_defaults));
891  }
892 
899  template <class T>
900  void storein(T& con, SQLQueryParms& p)
901  {
902  storein(con, str(p));
903  }
904 
906  template <class T>
907  void storein(std::vector<T>& con, const SQLTypeAdapter& s)
908  {
909  storein_sequence(con, s);
910  }
911 
913  template <class T>
914  void storein(std::deque<T>& con, const SQLTypeAdapter& s)
915  {
916  storein_sequence(con, s);
917  }
918 
920  template <class T>
921  void storein(std::list<T>& con, const SQLTypeAdapter& s)
922  {
923  storein_sequence(con, s);
924  }
925 
926 #if defined(HAVE_EXT_SLIST)
929  template <class T>
930  void storein(__gnu_cxx::slist<T>& con, const SQLTypeAdapter& s)
931  {
932  storein_sequence(con, s);
933  }
934 #elif defined(HAVE_GLOBAL_SLIST)
941  template <class T>
942  void storein(slist<T>& con, const SQLTypeAdapter& s)
943  {
944  storein_sequence(con, s);
945  }
946 #elif defined(HAVE_STD_SLIST)
952  template <class T>
953  void storein(std::slist<T>& con, const SQLTypeAdapter& s)
954  {
955  storein_sequence(con, s);
956  }
957 #endif
958 
960  template <class T>
961  void storein(std::set<T>& con, const SQLTypeAdapter& s)
962  {
963  storein_set(con, s);
964  }
965 
967  template <class T>
968  void storein(std::multiset<T>& con, const SQLTypeAdapter& s)
969  {
970  storein_set(con, s);
971  }
972 
983  template <class T>
984  Query& update(const T& o, const T& n)
985  {
986  reset();
987 
988  // Cast required for VC++ 2003 due to error in overloaded operator
989  // lookup logic. For an explanation of the problem, see:
990  // http://groups-beta.google.com/group/microsoft.public.vc.stl/browse_thread/thread/9a68d84644e64f15
991  MYSQLPP_QUERY_THISPTR << std::setprecision(16) <<
992  "UPDATE `" << o.table() << "` SET " << n.equal_list() <<
993  " WHERE " << o.equal_list(" AND ", sql_use_compare);
994  return *this;
995  }
996 
1005  template <class T>
1006  Query& insert(const T& v)
1007  {
1008  reset();
1009 
1010  MYSQLPP_QUERY_THISPTR << std::setprecision(16) <<
1011  "INSERT INTO `" << v.table() << "` (" <<
1012  v.field_list() << ") VALUES (" <<
1013  v.value_list() << ')';
1014  return *this;
1015  }
1016 
1030  template <class Iter>
1031  Query& insert(Iter first, Iter last)
1032  {
1033  reset();
1034 
1035  if (first != last) {
1036  // Build SQL for first item in the container. It's special
1037  // because we need the table name and field list.
1038  MYSQLPP_QUERY_THISPTR << std::setprecision(16) <<
1039  "INSERT INTO `" << first->table() << "` (" <<
1040  first->field_list() << ") VALUES (" <<
1041  first->value_list() << ')';
1042 
1043  // Now insert any remaining container elements. Be careful
1044  // hacking on the iterator use here: we want it to work
1045  // with containers providing only a forward iterator.
1046  Iter it = first;
1047  while (++it != last) {
1048  MYSQLPP_QUERY_THISPTR << ",(" << it->value_list() << ')';
1049  }
1050  }
1051 
1052  return *this;
1053  }
1054 
1067  template <class Iter, class InsertPolicy>
1068  Query& insertfrom(Iter first, Iter last, InsertPolicy& policy)
1069  {
1070  bool success = true;
1071  bool empty = true;
1072 
1073  reset();
1074 
1075  if (first == last) {
1076  return *this; // empty set!
1077  }
1078 
1079  typename InsertPolicy::access_controller ac(*conn_);
1080 
1081  for (Iter it = first; it != last; ++it) {
1082  if (policy.can_add(int(tellp()), *it)) {
1083  if (empty) {
1084  MYSQLPP_QUERY_THISPTR << std::setprecision(16) <<
1085  "INSERT INTO `" << it->table() << "` (" <<
1086  it->field_list() << ") VALUES (";
1087  }
1088  else {
1089  MYSQLPP_QUERY_THISPTR << ",(";
1090  }
1091 
1092  MYSQLPP_QUERY_THISPTR << it->value_list() << ')';
1093 
1094  empty = false;
1095  }
1096  else {
1097  // Execute what we've built up already, if there is anything
1098  if (!empty) {
1099  if (!exec()) {
1100  success = false;
1101  break;
1102  }
1103 
1104  empty = true;
1105  }
1106 
1107  // If we _still_ can't add, the policy is too strict
1108  if (policy.can_add(int(tellp()), *it)) {
1109  MYSQLPP_QUERY_THISPTR << std::setprecision(16) <<
1110  "INSERT INTO `" << it->table() << "` (" <<
1111  it->field_list() << ") VALUES (" <<
1112  it->value_list() << ')';
1113 
1114  empty = false;
1115  }
1116  else {
1117  // At this point all we can do is give up
1118  if (throw_exceptions()) {
1119  throw BadInsertPolicy("Insert policy is too strict");
1120  }
1121 
1122  success = false;
1123  break;
1124  }
1125  }
1126  }
1127 
1128  // We might need to execute the last query here.
1129  if (success && !empty && !exec()) {
1130  success = false;
1131  }
1132 
1133  if (success) {
1134  ac.commit();
1135  }
1136  else {
1137  ac.rollback();
1138  }
1139 
1140  return *this;
1141  }
1142 
1155  template <class Iter, class InsertPolicy>
1156  Query& replacefrom(Iter first, Iter last, InsertPolicy& policy)
1157  {
1158  bool success = true;
1159  bool empty = true;
1160 
1161  reset();
1162 
1163  if (first == last) {
1164  return *this; // empty set!
1165  }
1166 
1167  typename InsertPolicy::access_controller ac(*conn_);
1168 
1169  for (Iter it = first; it != last; ++it) {
1170  if (policy.can_add(int(tellp()), *it)) {
1171  if (empty) {
1172  MYSQLPP_QUERY_THISPTR << std::setprecision(16) <<
1173  "REPLACE INTO `" << it->table() << "` (" <<
1174  it->field_list() << ") VALUES (";
1175  }
1176  else {
1177  MYSQLPP_QUERY_THISPTR << ",(";
1178  }
1179 
1180  MYSQLPP_QUERY_THISPTR << it->value_list() << ')';
1181 
1182  empty = false;
1183  }
1184  else {
1185  // Execute what we've built up already, if there is anything
1186  if (!empty) {
1187  if (!exec()) {
1188  success = false;
1189  break;
1190  }
1191 
1192  empty = true;
1193  }
1194 
1195  // If we _still_ can't add, the policy is too strict
1196  if (policy.can_add(int(tellp()), *it)) {
1197  MYSQLPP_QUERY_THISPTR << std::setprecision(16) <<
1198  "REPLACE INTO `" << it->table() << "` (" <<
1199  it->field_list() << ") VALUES (" <<
1200  it->value_list() << ')';
1201 
1202  empty = false;
1203  }
1204  else {
1205  // At this point all we can do is give up
1206  if (throw_exceptions()) {
1207  throw BadInsertPolicy("Insert policy is too strict");
1208  }
1209 
1210  success = false;
1211  break;
1212  }
1213  }
1214  }
1215 
1216  // We might need to execute the last query here.
1217  if (success && !empty && !exec()) {
1218  success = false;
1219  }
1220 
1221  if (success) {
1222  ac.commit();
1223  }
1224  else {
1225  ac.rollback();
1226  }
1227 
1228  return *this;
1229  }
1230 
1240  template <class T>
1241  Query& replace(const T& v)
1242  {
1243  reset();
1244 
1245  MYSQLPP_QUERY_THISPTR << std::setprecision(16) <<
1246  "REPLACE INTO `" << v.table() << "` (" <<
1247  v.field_list() << ") VALUES (" << v.value_list() << ')';
1248  return *this;
1249  }
1250 
1265  template <class Iter>
1266  Query& replace(Iter first, Iter last)
1267  {
1268  reset();
1269  if (first != last) {
1270  // Build SQL for first item in the container. It's special
1271  // because we need the table name and field list.
1272  MYSQLPP_QUERY_THISPTR << std::setprecision(16) <<
1273  "REPLACE INTO " << first->table() << " (" <<
1274  first->field_list() << ") VALUES (" <<
1275  first->value_list() << ')';
1276 
1277  // Now insert any remaining container elements. Be careful
1278  // hacking on the iterator use here: we want it to work
1279  // with containers providing only a forward iterator.
1280  Iter it = first;
1281  while (++it != last) {
1282  MYSQLPP_QUERY_THISPTR << ",(" << it->value_list() << ')';
1283  }
1284  }
1285 
1286  return *this;
1287  }
1288 
1289 #if !defined(DOXYGEN_IGNORE)
1290  // Declare the remaining overloads. These are hidden down here partly
1291  // to keep the above code clear, but also so that we may hide them
1292  // from Doxygen, which gets confused by macro instantiations that look
1293  // like method declarations.
1294  mysql_query_define0(std::string, str)
1295  mysql_query_define0(SimpleResult, execute)
1296  mysql_query_define0(StoreQueryResult, store)
1297  mysql_query_define0(UseQueryResult, use)
1298  mysql_query_define1(storein_sequence)
1299  mysql_query_define1(storein_set)
1300  mysql_query_define1(storein)
1301 #endif // !defined(DOXYGEN_IGNORE)
1302 
1307 
1308 private:
1309  friend class SQLQueryParms;
1310 
1312  Connection* conn_;
1313 
1315  bool copacetic_;
1316 
1318  std::vector<SQLParseElement> parse_elems_;
1319 
1322  std::vector<std::string> parsed_names_;
1323 
1325  std::map<std::string, short int> parsed_nums_;
1326 
1328  std::stringbuf sbuffer_;
1329 
1331  void proc(SQLQueryParms& p);
1332 
1333  SQLTypeAdapter* pprepare(char option, SQLTypeAdapter& S, bool replace = true);
1334 };
1335 
1336 
1340 inline std::ostream& operator <<(std::ostream& os, Query& q)
1341 {
1342  return os << q.str();
1343 }
1344 
1345 
1346 } // end namespace mysqlpp
1347 
1348 #endif // !defined(MYSQLPP_QUERY_H)
1349 
Exception thrown when an insert policy is too strict to create a valid INSERT statement.
Definition: exceptions.h:457
Manages the connection to the database server.
Definition: connection.h:60
Disable exceptions in an object derived from OptionalExceptions.
Definition: noexceptions.h:120
Interface allowing a class to have optional exceptions.
Definition: noexceptions.h:72
A class for building and executing SQL queries.
Definition: query.h:124
void storein(std::deque< T > &con, const SQLTypeAdapter &s)
Specialization of storein_sequence() for std::deque.
Definition: query.h:914
Function for_each(Function fn)
Execute the query, and call a functor for each returned row.
Definition: query.h:547
std::string str()
Get built query as a C++ string.
Definition: query.h:283
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
bool exec()
Execute a built-up query.
Definition: query.h:317
Function for_each(const SQLTypeAdapter &query, Function fn)
Execute a query, and call a functor for each returned row.
Definition: query.h:526
Query & insert(Iter first, Iter last)
Insert multiple new rows.
Definition: query.h:1031
void storein_sequence(Sequence &con, const SQLTypeAdapter &s)
Executes a query, storing the result rows in an STL sequence container.
Definition: query.h:754
void storein(T &con, SQLQueryParms &p)
Store template query results into a container.
Definition: query.h:900
SQLQueryParms template_defaults
The default template parameters.
Definition: query.h:1306
Query & update(const T &o, const T &n)
Replace an existing row's data with new data.
Definition: query.h:984
Function store_if(Sequence &con, Function fn)
Execute the query, conditionally storing each row in a container.
Definition: query.h:662
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
std::string str(const SQLTypeAdapter &arg0)
Get built query as a C++ string with template query parameter substitution.
Definition: query.h:298
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
void storein(std::list< T > &con, const SQLTypeAdapter &s)
Specialization of storein_sequence() for std::list.
Definition: query.h:921
void storein(Container &con)
Execute a query, and store the entire result set in an STL container.
Definition: query.h:888
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
void storein_sequence(Sequence &con)
Execute a query, storing the result set in an STL sequence container.
Definition: query.h:735
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
Query & insert(const T &v)
Insert a new row.
Definition: query.h:1006
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
void storein(std::multiset< T > &con, const SQLTypeAdapter &s)
Specialization of storein_set() for std::multiset.
Definition: query.h:968
Function for_each(const SSQLS &ssqls, Function fn)
Run a functor for every row in a table.
Definition: query.h:571
Function store_if(Sequence &con, const SQLTypeAdapter &query, Function fn)
Execute a query, conditionally storing each row in a container.
Definition: query.h:607
void storein(std::vector< T > &con, const SQLTypeAdapter &s)
Specialization of storein_sequence() for std::vector.
Definition: query.h:907
void storein_set(Set &con)
Execute a query, storing the result set in an STL associative container.
Definition: query.h:806
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
void storein(std::set< T > &con, const SQLTypeAdapter &s)
Specialization of storein_set() for std::set.
Definition: query.h:961
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
Manages rows from a result set.
Definition: row.h:64
This class holds the parameter values for filling template queries.
Definition: qparms.h:49
Converts many different data types to strings suitable for use in SQL queries.
Definition: stadapter.h:74
A special std::set derivative for holding MySQL data sets.
Definition: myset.h:72
Holds information about the result of queries that don't return rows.
Definition: result.h:49
StoreQueryResult set type for "store" queries.
Definition: result.h:212
Exception thrown when something goes wrong in processing a "use" query.
Definition: exceptions.h:255
StoreQueryResult set type for "use" queries.
Definition: result.h:299
Row fetch_row() const
Returns the next row in a "use" query's result set.
Definition: result.cpp:172
This file includes top-level definitions for use both internal to the library, and outside it....
Declares the MySQL++-specific exception classes.
Declares the InsertPolicy classes.
Declares interface that allows exceptions to be optional.
Declares the template query parameter-related stuff.
Declares classes for holding information about SQL query results.
Declares the classes for holding row data from a result set.
Defines a class for building quoted and escaped SQL text.
Declares the SQLTypeAdapter class.
Declares the Transaction class.