$search
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