Main Page | Namespace List | Class Hierarchy | Class List | File List | Namespace Members | Class Members | File Members

sqldb.h

Go to the documentation of this file.
00001 // $Id: sqldb.h,v 1.16 2003/02/13 19:36:09 dvermeir Exp $ $Name:  $
00002 
00003 #ifndef DV_SQLDB_H
00004 #define DV_SQLDB_H
00005 
00006 #include <string>
00007 #include <sstream>
00008 #include <iostream>
00009 #include <vector>
00010 #include <stdexcept>
00011 #include <iterator>
00012 
00013 #include <dvutil/date.h>
00014 #include <dvutil/props.h>
00015 #include <dvmysql/vector_string_input_iterator.h>
00016 
00017 /*! \mainpage
00018 \author dvermeir@vub.ac.be
00019  
00020 <a href="../download/">Download</a>
00021 
00022 \section installation Installation
00023  
00024 Standard. See the INSTALL file in the top directory.
00025 
00026 Dependencies:
00027         <ul>
00028         <li> <a href="http://tinf2.vub.ac.be/~dvermeir/software/dv/index.html">dvutil</a>
00029         <li> <a href="http://mysql.com/">mysql </a>
00030         </ul>
00031 */
00032 
00033 /*! \file
00034     This file describes the dbms-independent classes:
00035 
00036     <ul>
00037     <li> Dv::Sql::Exception: thrown upon failure of some operations.
00038     <li> Dv::Sql::Field: describes a field in a table or query result.
00039     <li> Dv::Sql::Db: an open database connection.
00040     <li> Dv::Sql::Command: an sql command (query, update).
00041     <li> Dv::Sql::Command::iterator: an iterator for the result of a
00042          query.
00043     <li> Dv::Sql::Command_: an implementation class that must be subclassed
00044          for each particular DBMS.
00045     </ul>
00046 */
00047 
00048 //! The whole package lives in this namespace.
00049 namespace Dv {
00050 
00051 //! Namespace for dbms-independent classes.
00052 namespace Sql {
00053 
00054 //! Exception class used throughout the package.
00055 /*!
00056 Derived from runtime_error, i.e. the only useful member function
00057 is Dv::Sql::Exception::what() which returns constant C string
00058 describing the error.
00059 
00060 Most exceptions thrown are really logical errors (i.e. errors
00061 in the application or package source code).
00062 */
00063 class Exception: public std::runtime_error {
00064 public:
00065   //! Name of class, is prepended to each message argument of the constructor.
00066  static const std::string NAME;
00067   //! Constructor, prepends NAME to message to obtain runtime_error::what().
00068  Exception(const std::string& message): std::runtime_error(NAME+": "+message) {}
00069 };
00070 
00071 //! A field/column in a table or a query result.
00072 class Field {
00073 public:
00074   //! Field constructor. Users will never use this.
00075   /*! What are valid arguments is dbms-dependent.
00076   */
00077   Field(const std::string& name,const std::string& table, const std::string& type,
00078         const std::string& defaultvalue,
00079         bool isint,bool isflt, bool isstr, bool isbin, unsigned int sz);
00080 
00081   //! The name of the field.
00082   std::string   name() const    { return name_; }
00083   //! The name of the table containing this column.
00084   /*! For a query result (i.e. a Dv::Sql::Command), the table
00085       can be defined by the ``as'' clause in a ``select'' statement.
00086   */
00087   std::string   table() const   { return table_; }
00088   //! The type of this field. The return value is dbms-dependent.
00089   std::string   type() const    { return type_; }
00090   //! The default value (see the constructor).
00091   std::string   defaultvalue() const    { return default_; }
00092 
00093   //! Does the field have a numeric (int or float) type?
00094   bool          numeric() const { return int_ || float_ ; }
00095   //! Does the field have an integer type?
00096   bool          integer() const { return int_; }
00097   //! Does the field have floating point type?
00098   bool          real() const    { return float_; }
00099   //! Does the field have a binary type?
00100   bool          binary() const  { return binary_; }
00101   //! Does the field have a string type?
00102   bool          text() const    { return string_; }
00103 
00104   //! Convert mysql timestamp(14) value, e.g. 20010724110830 to Date.
00105   static Dv::Util::Date timestamp2date(const std::string& timestamp);
00106   //! Size of the field (in bytes).
00107   unsigned int  size() const    { return size_; }
00108 
00109   //! Print readable representation on ostream.
00110   /*! Example:
00111       \code
00112        LONG[11] test.number
00113        STRING[32] test.word
00114        DATETIME[19] structuur2.wanneer
00115        VAR_STRING[100] structuur2.info
00116        TIMESTAMP[14] structuur2.time_stamp        
00117       \endcode
00118   */
00119   friend std::ostream& operator<<(std::ostream&,const Field&);
00120 private:
00121   std::string   name_;
00122   std::string   table_;
00123   std::string   type_;
00124   std::string   default_;
00125 
00126   bool          int_;
00127   bool          float_;
00128   bool          string_;
00129   bool          binary_;
00130   unsigned int  size_;
00131 
00132 };
00133 
00134 class Command_;
00135 class Command;
00136 
00137 //! An connection to an SQL database.
00138 class Db {
00139 
00140 //! Friend.
00141 friend class Command;
00142 
00143 public:
00144   //! Since this class will be subclassed, its destructor must be virtual.
00145   /*! The destructor will close the connection.
00146   */
00147   virtual ~Db() {}
00148 
00149   //! Return true iff status is ok; e.g. db was succesfully opened.
00150   bool          ok() const              { return ok_; }
00151   //! Same as Dv::Sql::Db::ok().
00152   operator      bool() const            { return ok_; }
00153   //! Same as !Dv::Sql::Db::ok().
00154   bool          operator!() const       { return !ok_; }
00155 
00156   //! Return string representation of last error.
00157   std::string   err() const             { return err_; }
00158   //! Name of host machine on which database resides.
00159   std::string   host() const            { return host_; }
00160   //! Name of current database of connection.
00161   std::string   database() const        { return name_; }
00162 
00163   //! Logging is turned on if log()!=0.
00164   /*! The amount of logging is decided by the DBMS-dependent classes.
00165       E.g. Dv::MySql::Db logs the execution of every command as
00166       well as indication of the result.
00167   */
00168   std::ostream* log() const             { return log_; }
00169   //! Turn logging on/off, see Db::log().
00170   void          log(std::ostream* os)   { log_ = os; }
00171 
00172   //! Switch connection to database, return true iff succeeded.
00173   virtual bool           database(const std::string& database) = 0;
00174   //! Return names of available databases.
00175   virtual std::vector<std::string> databases() = 0;
00176   //! Return names of tables in databases.
00177   virtual std::vector<std::string> tables() = 0;
00178   //! Return fields in table.
00179   virtual std::vector<Field> fields(const std::string& table) = 0;
00180 
00181 protected:
00182   //! Set status.
00183   bool          ok(bool b)                      { return ok_ = b; }
00184   //! Set error string returned by Dv::Sql::err().
00185   void          err(const std::string& s)               { err_ = s; }
00186   //! Set database name.
00187   void          name(const std::string& dbname) { name_ = dbname; }
00188 
00189 
00190   //! Return dbms-specific command.
00191   /*! Factory method; a concrete subclass X of Db implements this
00192       to return (a pointer to) an instance of the subclass of Command_
00193       corresponding to X's Command_.
00194   */
00195   virtual Command_*     command_(Command&) = 0;
00196 
00197   //! Constructor.
00198   /*! The constructor takes the name of the database
00199       and the name of the host where the database resides.
00200       If name == 0, there is no database yet, if host == 0,
00201       we use "localhost"
00202 
00203       Copy ctor and assignment are forbidden.
00204   */
00205   Db(const char* name,const char* host);
00206 
00207 private:
00208   std::string   host_;
00209   bool          ok_;
00210   std::string   err_;
00211   std::ostream* log_;
00212 
00213   //! Name of database, may be "".
00214   std::string   name_; 
00215 
00216   //! Cctor is forbidden.
00217   Db(const Db&);
00218   //! Assignment is forbidden.
00219   Db&           operator=(const Db&);
00220 
00221 };
00222 
00223 
00224 //! A Command represents a command, e.g. a query, for a Dv::Sql::Db.
00225 /*! Command is a dbms-independent proxy class for the dbms-dependent
00226     Command_. A Command object has a pointer to a companion Command_
00227     object, which has been created using Dv::Sql::Db::command_(). 
00228 
00229     This is an alternative for inheritance:
00230     instead of subclassing Command, the ``subclass part'' is
00231     available in *cmd_.
00232 
00233     This has the advantage that only the definition of the
00234     database object ``db'' derived from Dv::Sql::Db depends on the actual
00235     DBMS used. All other database manipulatsions can be done
00236     through normal Dv::Sql::Command objects, which are initialized
00237     using a referrence to a Dv::Sql::Db. Consequently, applications
00238     are more independent of the actual underlying DBMS.
00239 
00240     Example:
00241     \code
00242     MySql::Db db(...);
00243 
00244     std::string name;
00245     Sql::Command query("select * from person where name = ");
00246     query << name;
00247     if (q.exec())
00248       for (Sql::Command::iterator i=q.begin(); i!=q.end(); ++i) 
00249         cout << i(0) << "\t" << i(1) << endl;
00250     \endcode
00251     Commands contain a text. This text is built using
00252     Command::operator<<(..).
00253 */
00254 class Command {
00255 
00256 public:
00257 
00258   class iterator;
00259   //! Friend.
00260   friend class Db;
00261   //! Friend.
00262   friend class iterator;
00263   //! Friend.
00264   friend class Command_;
00265 
00266 
00267   //! Constructor, text is initial text of command.
00268   /*! Example
00269       \code
00270       Sql::Command      q("insert into person values (");
00271       // rest of command is inserted using operator<<
00272       \endcode
00273   */
00274   Command(Db& db,const char* text=0);
00275   //! Destructor also destroys any result data.
00276   ~Command();
00277 
00278   //! Status of command.
00279   bool          ok() const      { return ok_; }
00280   //! Same as Dv::Sql::Command::ok().
00281   operator      bool() const    { return ok_; }
00282   //! Error message.
00283   std::string   err() const     { return err_; }
00284   //! Return true iff the command has already been executed.
00285   /*! Calling Dv::Sql::Command::exec() twice is a noop.
00286   */
00287   bool          ran() const     { return ran_; }
00288   //! Return database connection with which this command is associated.
00289   Db&           db(); // see below, for inline definition
00290   //! Return text of command.
00291   /*! Example
00292     \code
00293     std::string name("jane");
00294     Sql::Command query("select * from person where name = ");
00295     query << name;
00296     cout << query.text();
00297     \endcode
00298     will print
00299     \code
00300     select * from person where name = 'jane'
00301     \endcode
00302   */
00303   std::string   text()  { frozen_ = true; return text_.str();}
00304                                                     
00305   //! Return field information for query result.
00306   const std::vector<Field>&     fields();
00307   //! Return number of rows in query result.
00308   unsigned int  nrows()         { return nrows_; }
00309   //! Return number of columns in query result.
00310   unsigned int  ncols()         { return ncols_; }
00311   //! Return logical pointer to first row of the result.
00312   iterator      begin();
00313   //! Return logical pointer to past the end of the query result.
00314   iterator      end();
00315 
00316   //! Check whether a rowno r is valid, i.e. the r'th row is available
00317   bool          valid(int r) const;
00318 
00319   //! Append a string to the command text; the string will be escaped and quoted.
00320   /*! 
00321       E.g. after
00322       \code
00323       Db::Sql::Db& db;
00324   
00325       Dv::Sql::Command  q(db,"select * from person");
00326       q << "where name ="  << std::string("joe's nightamere");
00327       \endcode
00328       q.text_ will contain
00329       \code
00330       select * from person where name = 'joe\'s nightmare'
00331       \endcode
00332 
00333       Note that Dv::Sql::Command::operator<<(const char*) does not escape or quote.
00334   */
00335   Command&      operator<<(const std::string&) throw (Exception);
00336   //! Append a string to the command text.
00337   Command&      operator<<(const char*) throw (Exception);
00338   //! Append an int to the command text.
00339   Command&      operator<<(int) throw (Exception);
00340   //! Append an unsigned int to the command text.
00341   Command&      operator<<(unsigned int) throw (Exception);
00342   //! Append a short to the command text.
00343   Command&      operator<<(short) throw (Exception);
00344   //! Append an unsigned short to the command text.
00345   Command&      operator<<(unsigned short) throw (Exception);
00346   //! Append a long to the command text.
00347   Command&      operator<<(long) throw (Exception);
00348   //! Append an unsigned long to the command text.
00349   Command&      operator<<(unsigned long) throw (Exception);
00350   //! Append a float to the command text.
00351   Command&      operator<<(float) throw (Exception);
00352   //! Append a double to the command text.
00353   Command&      operator<<(double) throw (Exception);
00354 
00355   //! Execute the query, status is determined by underlying DBMS.
00356   bool          exec(); // inline definition at the end of this file
00357   /** Return auto_increment id of last insert. */
00358   unsigned int insertid() const;
00359 private:
00360   bool          ran_;
00361   std::string   err_;
00362   bool          ok_;
00363   std::ostringstream text_;
00364   bool          frozen_; // after text_.str() has been used
00365 
00366 
00367   //! Nrows_ is # of rows in query answer, only valid if ran() && ok()
00368   unsigned long nrows_;
00369   //! Ncols_ is # of columns in query answer, only valid if ran() && ok()
00370   unsigned long ncols_;
00371   
00372 
00373   //! Associated dbms-dependent object.
00374   /*! Many functions such as Dv::Sql::Command::exec() are delegated
00375       to cmd_->exec().
00376   */
00377   Command_      *cmd_;
00378 
00379   //! Retrieve the r'th row of the result ( 0<= r < nrows_ ).
00380   /*! Delegated to cmd_. */
00381   void  fetch(std::vector<std::string>& v,unsigned int r) throw (Exception);
00382   //! Retrieve the r'th row and c'th column of the result ( 0<= r < //nrows_ ).
00383   /*! Delegated to cmd_. */
00384   void  fetch(std::string& s,unsigned int r,unsigned int c) throw (Exception);
00385 
00386 
00387   //! Cctor is forbidden.
00388   Command(const Command&); 
00389   //! Assignment is forbidden.
00390   Command&      operator=(const Command&);
00391 
00392   void          nrows(unsigned int n)   { nrows_ = n; }
00393   void          ncols(unsigned int n)   { ncols_ = n; }
00394   void          run()                   { ran_ = true; }
00395   void          err(const char*s)       { err_ = std::string(s); }
00396   void          ok(bool b)              { ok_ = b; }
00397 
00398 };
00399 
00400 //! A logical pointer (input iterator) inside the query result of a Dv::Sql::Command.
00401 /*! A valid iterator in the range [begin,end[ points to
00402     a row of the query result.
00403 
00404     Its value type is the type of a row in the query result, i.e.
00405     a vector of strings (classes like Dv::Int can be used to
00406     convert to numeric types, see dvutil).
00407 */
00408 class Command::iterator: public vector_string_input_iterator {
00409 
00410 //! Friend.
00411 friend class Command;
00412 
00413 public:
00414   //! Make the iterator point to the next row in the result: prefix version.
00415   iterator&     operator++() throw (Exception);
00416   //! Make the iterator point to the next row in the result: postfix version.
00417   iterator      operator++(int) { iterator tmp=*this; ++*this; return tmp; }
00418 
00419   //! Dereference to the current row.
00420   /*! NULL is represented by the std::string ``NULL''.
00421   */
00422   std::vector<std::string>      operator*() const throw (Exception);
00423 
00424   //! Compare two iterators.
00425   bool  operator==(const iterator&j) const {
00426                         return row_ == j.row_ && &cmd_ == &j.cmd_; }
00427   //! Compare two iterators.
00428   bool  operator!=(const iterator&j) const {
00429                         return row_ != j.row_ || &cmd_ != &j.cmd_; }
00430 
00431   //! Non standard operator: get c'th column of current row.
00432   /*! Example
00433       \code
00434       MySql::Db db(...);
00435   
00436       std::string name;
00437       Sql::Command query("select * from person where name = ");
00438       query << name;
00439       if (q.exec())
00440         for (Sql::Command::iterator i=q.begin(); i!=q.end(); ++i) 
00441           cout << i(0) << "\t" << i(1) << endl;
00442       \endcode
00443   */
00444   std::string operator()(unsigned int c) const throw (Exception);
00445 
00446   //! Return command associated with iterator.
00447   Command& command() const { return cmd_; }
00448 private:
00449   enum { END = -1, BEGIN = 0 };
00450 
00451   Command&      cmd_;
00452   int           row_;   // may be BEGIN || END || 0<= row_ < cmd_.nrows_;
00453 
00454   iterator(Command& cmd,int r): cmd_(cmd), row_(r) {}
00455 };
00456 
00457 //! Proxy class for Sql::Db::Command. Not used by end users.
00458 /*! This class needs to be subclassed for a particular DBMS.
00459     A Dv::Sql::Command_ object forms a pair with a Dv::Sql::Command
00460     object: each contains a reference (or pointer) to the other.
00461     The Dv::Sql::Command_ object associated with a Dv::Sql::Command
00462     object cmd is created using the Dv::Sql::Db virtual member 
00463     function Sql::Db::command_(cmd).
00464     
00465     There is delegation in both ways: Dv::Sql::Command_ uses 
00466     Dv::Sql::Command to perform some DBMS-independent operations and
00467     Dv::Sql::Command delegates all DBMS-dependent
00468     operations to Dv::Sql::Command_.
00469 */
00470 class Command_ {
00471 //! Friend.
00472 friend class Command;
00473 protected:
00474   //! Return number of rows in the query result.
00475   unsigned int  nrows()                 { return cmd_.nrows(); }
00476   //! Set number of rows in the query result.
00477   void          nrows(unsigned int n)   { cmd_.nrows(n); }
00478   //! Set number of columns in the query result.
00479   void          ncols(unsigned int n)   { cmd_.ncols(n); }
00480   //! Mark the command (and associated Dv::Sql::Command) as having been executed.
00481   void          run()                   { cmd_.run(); }
00482   //! Return status string of this command.
00483   std::string   err()                   { return cmd_.err(); }
00484   //! Set status string of this command.
00485   void          err(const char*s)       { cmd_.err(s); }
00486   //! Set status of this command.
00487   void          ok(bool b)              { cmd_.ok(b); }
00488   //! Retrieve text of the command as a string stream.
00489   std::ostringstream&   textstream()            { return cmd_.text_; }
00490 
00491   //! Associated DBMS-independent Dv::Sql::Command object.
00492   Command&      cmd_;
00493 
00494   //! Constructor: the associated Dv::Sql::Command object must already exist.
00495   Command_(Command& cmd): cmd_(cmd) {}
00496   //! Destructor, virtual because it will be subclassed.
00497   virtual ~Command_() {}
00498   //! Actually execute the command, DBMS-dependent.
00499   virtual bool  exec() = 0;
00500   //! Return database connection associated with this command.
00501   virtual Db&   db() = 0;
00502 
00503   //! Write s in properly quoted and escaped form to this->textstream()
00504   virtual void  escape(const std::string& s);
00505   //! Low level retrieval: put row # r from query result into the parameter.
00506   virtual void  fetch(std::vector<std::string>&,unsigned int r) throw (Exception) = 0;
00507   //! Low level retrieval: get column c from row # r from query result.
00508   /*! An exception is thrown if any of r or c is out of range.
00509   */
00510   virtual void  fetch(std::string&,unsigned int r,unsigned int c) throw (Exception);
00511   //! Return field information for the query result.
00512   virtual const std::vector<Field>&     fields() = 0;
00513   /** Return id of auto_increment field of last insertion */
00514   virtual unsigned int insertid() const;
00515 
00516 private:
00517   Command_(const Command_&);
00518   Command_& operator=(const Command_&);
00519 
00520 };
00521 
00522 inline void
00523 Command::fetch(std::vector<std::string>& v,unsigned int r) throw (Exception) {
00524 cmd_->fetch(v,r);
00525 }
00526 
00527 inline  void
00528 Command::fetch(std::string& s,unsigned int r,unsigned int c) throw (Exception) {
00529 cmd_->fetch(s,r,c);
00530 }
00531 
00532 inline bool Command::exec() { return cmd_->exec(); }
00533 inline const std::vector<Field>& Command::fields() { return cmd_->fields(); }
00534 inline Db& Command::db() { return cmd_->db(); }
00535 inline Command::iterator Command::end() { return iterator(*this,iterator::END); }
00536 inline unsigned int Command::insertid() const { return cmd_->insertid(); }
00537 
00538 }
00539 }
00540 
00541 //! Update props to reflect query result row represented by iterator.
00542 /*! Updat props such that props[fieldname] = result for each fieldname
00543     of the command associated with the iterator.
00544 */
00545 Dv::Util::Props& operator<<(Dv::Util::Props&, const Dv::Sql::Command::iterator&);
00546 
00547 #endif

dvmysql-0.4.11 [15 February, 2004]