db_field.h
Go to the documentation of this file.
00001 /*********************************************************************
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2009, Willow Garage, Inc.
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of the Willow Garage nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
00033  *********************************************************************/
00034 
00035 // Author(s): Matei Ciocarlie
00036 
00037 #ifndef _DB_FIELD_H_
00038 #define _DB_FIELD_H_
00039 
00040 #include <stdio.h>
00041 
00042 #include <vector>
00043 #include <map>
00044 #include <string>
00045 #include <sstream>
00046 #include <iostream>
00047 #include <iomanip>
00048 
00049 #include <boost/format.hpp>
00050 
00051 //for memcpy
00052 #include <cstring>
00053 
00054 namespace database_interface {
00055 
00056 class DBClass;
00057 
00059 
00072 class DBFieldBase
00073 {
00074  private:
00076 
00077   const DBFieldBase& operator = (const DBFieldBase &rhs);
00078  public:
00083   enum Type{TEXT, BINARY};
00084  protected:
00086   Type type_;
00088   DBClass* owner_;
00090 
00093   bool write_permission_;
00095   bool read_from_database_;
00097   bool write_to_database_;
00099   std::string name_;
00101   std::string table_name_;
00103   std::string sequence_name_;
00104 
00106  DBFieldBase(DBClass *owner, const DBFieldBase *other) : 
00107   type_(other->type_), owner_(owner),
00108     write_permission_(other->write_permission_), read_from_database_(other->read_from_database_), 
00109     write_to_database_(other->write_to_database_), 
00110     name_(other->name_), table_name_(other->table_name_) {}
00111 
00112  public:
00113  DBFieldBase(Type type, DBClass* owner, std::string name, std::string table_name, bool write_permission) : 
00114     type_(type), owner_(owner),
00115     write_permission_(write_permission), read_from_database_(true), write_to_database_(true), 
00116     name_(name), table_name_(table_name) {}
00117 
00118   Type getType() const {return type_;}
00119 
00121   virtual bool fromString(const std::string &str) = 0;
00123   virtual bool toString(std::string &str) const = 0;
00124 
00126   virtual bool fromBinary(const char* binary, size_t length) = 0;
00128 
00130   virtual bool toBinary(const char* &binary, size_t &length) const = 0;
00131 
00132   DBClass* getOwner(){return owner_;}
00133   const DBClass* getOwner() const {return owner_;}
00134 
00135   bool getReadFromDatabase() const {return read_from_database_;}
00136   void setReadFromDatabase(bool sync) {read_from_database_ = sync;}
00137 
00138   bool getWriteToDatabase() const {return write_to_database_;}
00139   void setWriteToDatabase(bool sync) {write_to_database_ = sync;}
00140 
00141   bool getWritePermission() const {return write_permission_;}
00142 
00143   void setReadWrite(bool sync) 
00144   {
00145     setReadFromDatabase(sync);
00146     setWriteToDatabase(sync);
00147   }
00148 
00149   std::string getName() const {return name_;}
00150   std::string getTableName() const {return table_name_;}
00151   std::string getSequenceName() const {return sequence_name_;}
00152 
00153   void setSequenceName(std::string seq) {sequence_name_ = seq;}
00154 };
00155 
00157 template<class V>
00158 std::istream& operator >> (std::istream &iss, std::vector<V> &vec)
00159 {
00160   char c;
00161   iss >> c;
00162   if (iss.eof()) 
00163   {
00164     iss.clear();
00165     return iss;
00166   }
00167   if (iss.fail() || c != '{') 
00168   {
00169     iss.clear(std::ios::failbit);
00170     return iss;
00171   }
00172   
00173   while(1)
00174   {
00175     V val;
00176     iss >> val;
00177     if (iss.eof() || iss.fail()) 
00178     {
00179       iss.clear(std::ios::failbit);      
00180       return iss;
00181     }
00182     vec.push_back(val);
00183     
00184     iss >> c;
00185     if (iss.eof() || iss.fail()) 
00186     {
00187       iss.clear(std::ios::failbit);      
00188       return iss;
00189     }
00190     if (c == '}') break;
00191     if (c != ',') 
00192     {
00193       iss.clear(std::ios::failbit);      
00194       return iss;
00195     }
00196   }
00197   return iss;  
00198 }
00199 
00201 template <class V>
00202 std::ostream& operator << (std::ostream &str, const std::vector<V> &vec)
00203 {
00204   str << "{";
00205   for (size_t i=0; i<vec.size(); i++)
00206   {
00207     if (i!=0) str << ",";
00208     str << vec[i];
00209     if (str.fail()) return str;
00210   }
00211   str << "}";
00212   return str;
00213 }
00214 
00215 // We need to use a trait class here. Templated functions are not
00216 // flexible enough since they do not support partial specialization.
00217 template<typename T>
00218 struct DBStreamable
00219 {
00221   static bool streamableFromString(T &data, const std::string &str)
00222   {
00223     std::istringstream iss(str);
00224     return !(iss >> data).fail();
00225   }
00226 
00228   static bool streamableToString(const T &data, std::string &str)
00229   {
00230     std::ostringstream oss;
00231     // Only use 5 digits after the comma. Hopefully this solves an
00232     // issue with reading data from the database and comparing against
00233     // it later.
00234     oss << std::setprecision(30) << data;
00235     if (oss.fail()) return false;
00236     str = oss.str();
00237     return true;
00238   }
00239 };
00240 
00241 template<>
00242 struct DBStreamable<double>
00243 {
00245   static bool streamableFromString(double &data, const std::string &str)
00246   {
00247     // We need to restrict to only 5 digits after point. Otherwise
00248     // comparison is hell. Serialization uses only 5 digits.
00249     size_t point_pos = str.find('.');
00250     std::istringstream iss(str.substr(0, point_pos == std::string::npos ? point_pos : point_pos + 6));
00251     return !(iss >> data).fail();
00252   }
00253 
00255   static bool streamableToString(double data, std::string &str)
00256   {
00257     std::ostringstream oss;
00258     // Only use 5 digits after the comma. Hopefully this solves an
00259     // issue with reading data from the database and comparing against
00260     // it later.
00261     oss << boost::format("%.5f") % data;
00262     if (oss.fail()) return false;
00263     str = oss.str();
00264     return true;
00265   }
00266 };
00267 
00269 
00276 template <class T>
00277 class DBFieldData : public DBFieldBase
00278 {
00279  protected:
00280   T data_;
00281 
00283 
00287  DBFieldData(DBClass *owner, const DBFieldData *other) : DBFieldBase(owner, other) 
00288     {}
00289 
00290   void copy(const DBFieldData<T> *other)
00291   {
00292     if (this->type_==DBFieldBase::TEXT)
00293     {
00294       //hmm.. these can technically fail. What then?
00295       std::string copy_str;
00296       if (!other->toString(copy_str) || !this->fromString(copy_str))
00297       {
00298         std::cerr << "ERROR: database field ASCII copy failed during copy constructor of field " 
00299                   << this->name_ 
00300                   << ". This is currently an unhandled error, and will probably have serious effects.\n";
00301       }
00302       //std::cerr << "Copying field " << this->name_ << ". String: " << copy_str << "\n";
00303     }
00304     else if (this->type_==DBFieldBase::BINARY)
00305     {
00306       //hmm.. these can technically fail. What then?
00307       const char *copy_bin; size_t length;
00308       if (!other->toBinary(copy_bin, length) || !this->fromBinary(copy_bin, length))
00309       {
00310         std::cerr << "ERROR: database field BINARY copy failed during copy constructor of field " 
00311                   << this->name_ 
00312                   << ". This is currently an unhandled error, and will probably have serious effects.\n";
00313       }
00314     }
00315   }
00316 
00317  public:
00318   DBFieldData(Type type, DBClass* owner, std::string name, std::string table_name, bool write_permission) : 
00319     DBFieldBase(type, owner, name, table_name, write_permission){}
00320 
00321   const T& get() const {return data_;}
00322 
00323   T& get() {return data_;}
00324 
00325   const T& data() const {return data_;}
00326 
00327   T& data() {return data_;}
00328 
00329   virtual bool fromString(const std::string &str)
00330   {
00331     return DBStreamable<T>::streamableFromString(this->data_, str);
00332   }
00333 
00334   virtual bool toString(std::string &str) const
00335   {
00336     return DBStreamable<T>::streamableToString(this->data_, str);
00337   }
00338 
00339   virtual bool fromBinary(const char* /*binary*/, size_t /*length*/) {return false;}
00340   virtual bool toBinary(const char* &/*binary*/, size_t &/*length*/) const {return false;}
00341 };
00342 
00344 
00347 template <class T>
00348 class DBField : public DBFieldData<T>
00349 {
00350  public:
00351   DBField(DBFieldBase::Type type, DBClass *owner, std::string name, std::string table_name, bool write_permission) : 
00352     DBFieldData<T>(type, owner, name, table_name, write_permission) {}
00353 
00354  DBField(DBClass *owner, const DBField<T> *other) : DBFieldData<T>(owner, other) 
00355  {
00356    this->copy(other);
00357  }
00358 
00359 };
00360 
00362 template <>
00363 class DBField<bool> : public DBFieldData<bool>
00364 {
00365  public:
00366   DBField(Type type, DBClass *owner, std::string name, std::string table_name, bool write_permission) : 
00367     DBFieldData<bool>(type, owner, name, table_name, write_permission) {}
00368 
00369   DBField(DBClass *owner, const DBField<bool> *other) : DBFieldData<bool>(owner, other) 
00370   {
00371     this->copy(other);
00372   }
00373 
00374   virtual bool fromString(const std::string &str) 
00375   {
00376     if (str=="true" || str=="t" || str == "True" || str == "TRUE") this->data_ = true;
00377     else if (str=="false" || str=="f" || str == "False" || str == "FALSE") this->data_ = false;
00378     else return false;
00379     return true;
00380   }
00381 
00382   virtual bool toString(std::string &str) const 
00383   {
00384     if (this->data_) str="true";
00385     else str = "false";
00386     return true;
00387   }
00388 };
00389 
00390 
00392 template <>
00393 class DBField< std::vector<char> > : public DBFieldData< std::vector<char> >
00394 {
00395  public:
00396   DBField(Type type, DBClass *owner, std::string name, std::string table_name, bool write_permission) : 
00397     DBFieldData< std::vector<char> >(type, owner, name, table_name, write_permission) {}
00398 
00399  DBField(DBClass *owner, const DBField< std::vector<char> > *other) : DBFieldData< std::vector<char> >(owner, other) 
00400       {
00401         this->copy(other);
00402       }
00403   
00404   virtual bool fromBinary(const char* binary, size_t length) 
00405   {
00406     data_.resize(length);
00407     memcpy(&(data_[0]), binary, length);
00408     return true;
00409   }
00410 
00411   virtual bool toBinary(const char* &binary, size_t &length) const 
00412   {
00413     length = data_.size();
00414     if (!data_.empty())
00415     {
00416       binary = &(data_[0]);
00417     }
00418     return true;
00419   }
00420 };
00421 
00423 template <>
00424 class DBField<std::string> : public DBFieldData<std::string>
00425 {
00426  public:
00427 
00428   DBField(Type type, DBClass *owner, std::string name, std::string table_name, bool write_permission) : 
00429     DBFieldData<std::string>(type, owner, name, table_name, write_permission) {}
00430 
00431   DBField(DBClass *owner, const DBField< std::string > *other) : DBFieldData< std::string >(owner, other) 
00432       {
00433         this->copy(other);
00434       }
00435 
00436   virtual bool fromString(const std::string &str) {data_ = str; return true;}
00437   virtual bool toString(std::string &str) const {str = data_; return true;}
00438 };
00439 
00441 template <>
00442 class DBField< std::vector<std::string> > : public DBFieldData< std::vector<std::string> >
00443 {
00444  public:
00445   DBField(Type type, DBClass *owner, std::string name, std::string table_name, bool write_permission) : 
00446     DBFieldData< std::vector<std::string> >(type, owner, name, table_name, write_permission) {}
00447 
00448  DBField(DBClass *owner, const DBField< std::vector<std::string> > *other) : 
00449     DBFieldData< std::vector<std::string> >(owner, other) 
00450       {
00451         this->copy(other);
00452       }
00453 
00454   virtual bool fromString(const std::string &str) 
00455   {
00456     if (str.empty()) return true;
00457     if (str.at(0) != '{') return false;
00458 
00459     size_t pos = 1;
00460     bool done = false;
00461     while (!done)
00462     {
00463       if (pos >= str.size()) return false;
00464       size_t new_pos = str.find(',',pos);
00465       if (new_pos == std::string::npos)
00466       {
00467         new_pos = str.find('}',pos);
00468         if (new_pos == std::string::npos) return false;
00469         done = true;
00470       }
00471       if (new_pos == pos) return false;
00472       this->data_.push_back(str.substr(pos, new_pos-pos));
00473       pos = new_pos + 1;
00474     }
00475     return true;
00476   }
00477 };
00478 
00479 } //namespace database_interface
00480 
00481 #endif
00482 


sql_database
Author(s): Matei Ciocarlie and Lorenz Mosenlechner
autogenerated on Fri Aug 28 2015 13:11:16