00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef __PION_SQLITEDATABASE_HEADER__
00021 #define __PION_SQLITEDATABASE_HEADER__
00022
00023 #include <pion/PionConfig.hpp>
00024 #include <pion/PionException.hpp>
00025 #include <pion/platform/Database.hpp>
00026 #include "../../sqlite/pion-sqlite.h"
00027
00028 #if SQLITE_VERSION_NUMBER != 3007005
00029 #error Incorrect version of Pion-SQLite
00030 #endif
00031
00032 namespace pion {
00033 namespace plugins {
00034
00035
00039 class SQLiteDatabase :
00040 public pion::platform::Database
00041 {
00042 PionLogger m_logger;
00043
00044 public:
00045
00047 class EmptyFilenameException : public PionException {
00048 public:
00049 EmptyFilenameException(const std::string& database_id)
00050 : PionException("SQLiteDatabase configuration is missing a required Filename parameter: ", database_id) {}
00051 };
00052
00054 class SQLiteAPIException : public PionException {
00055 public:
00056 SQLiteAPIException(const std::string& sqlite_error_msg)
00057 : PionException("SQLiteDatabase API error: ", sqlite_error_msg) {}
00058 };
00059
00061 class DBStillOpen : public PionException {
00062 public:
00063 DBStillOpen(const std::string& database_id)
00064 : PionException("SQLiteDatabase DROP on table which is still open: ", database_id) {}
00065 };
00066
00067
00071 SQLiteDatabase(void)
00072 : pion::platform::Database("pion.SQLiteDatabase"), m_logger(PION_GET_LOGGER("pion.SQLiteDatabase")),
00073 m_sqlite_db(NULL), m_error_ptr(NULL), m_cache_size(0), m_partition(0)
00074 {
00075 }
00076
00078 virtual ~SQLiteDatabase()
00079 {
00080 m_query_map.clear();
00081 close();
00082 }
00083
00089 virtual pion::platform::DatabasePtr clone(void) const;
00090
00096 virtual void open(unsigned partition = 0);
00097
00099 virtual void close(void);
00100
00102 std::string dbPartition(std::string name, unsigned partition)
00103 {
00104 if (partition) {
00105 char buff[10];
00106 sprintf(buff, "_%03u.db", partition);
00107 std::string::size_type i = 0;
00108 if ((i = name.find(".db", i)) != std::string::npos)
00109 name.replace(i, strlen(".db"), buff);
00110 else
00111 name += buff;
00112 }
00113 return name;
00114 }
00115
00117 virtual boost::uint64_t getCache(CACHEPARAM what)
00118 {
00119 switch (what) {
00120 case CACHE_INDEX_ROW_OVERHEAD:
00121 return 9;
00122 case CACHE_PAGE_CACHE_SIZE:
00123 return m_cache_size;
00124 case CACHE_PAGE_UTILIZATION:
00125 return 85;
00126 case DB_FILE_SIZE:
00127 {
00128 boost::filesystem::path f(dbPartition(m_database_name, m_partition).c_str(), boost::filesystem::native );
00129 if (!boost::filesystem::exists(f) || !boost::filesystem::is_regular(f))
00130 return 0;
00131 return boost::filesystem::file_size(f);
00132 }
00133 }
00134 return 0;
00135 }
00136
00138 virtual bool is_open(void) const { return m_sqlite_db != NULL; }
00139
00146 virtual void runQuery(const std::string& sql_query, const boost::regex& suppress);
00147
00154 virtual pion::platform::QueryPtr addQuery(pion::platform::QueryID query_id,
00155 const std::string& sql_query);
00156
00165 virtual void createTable(const pion::platform::Query::FieldMap& field_map,
00166 std::string& table_name,
00167 const pion::platform::Query::IndexMap& index_map,
00168 unsigned partition);
00169
00176 virtual void dropTable(std::string& table_name, unsigned partition = 0);
00177
00184 virtual bool tableExists(std::string& table_name, unsigned partition = 0);
00185
00194 virtual pion::platform::QueryPtr prepareInsertQuery(const pion::platform::Query::FieldMap& field_map,
00195 const std::string& table_name);
00196
00197 virtual pion::platform::QueryPtr prepareInsertIgnoreQuery(const pion::platform::Query::FieldMap& field_map,
00198 const std::string& table_name);
00199
00208 virtual pion::platform::QueryPtr prepareFullQuery(const std::string& query, const boost::regex& suppress);
00209
00215 virtual pion::platform::QueryPtr getBeginTransactionQuery(void);
00216
00222 virtual pion::platform::QueryPtr getCommitTransactionQuery(void);
00223
00231 virtual void setConfig(const pion::platform::Vocabulary& v, const xmlNodePtr config_ptr);
00232
00238 static inline void throwAPIException(sqlite3 *db_ptr) {
00239 PION_ASSERT(db_ptr != NULL);
00240 std::string error_msg(sqlite3_errmsg(db_ptr));
00241 throw SQLiteAPIException(error_msg);
00242 }
00243
00244
00245 protected:
00246
00248 inline std::string getSQLiteError(void);
00249
00250
00254 class SQLiteQuery
00255 : public pion::platform::Query
00256 {
00257 public:
00258
00260 virtual ~SQLiteQuery() { sqlite3_finalize(m_sqlite_stmt); }
00261
00268 SQLiteQuery(const std::string& sql_query, sqlite3 *db_ptr);
00269
00275 virtual void bindNull(unsigned int param) {
00276 if (sqlite3_bind_null(m_sqlite_stmt, param+1) != SQLITE_OK)
00277 SQLiteDatabase::throwAPIException(m_sqlite_db);
00278 }
00279
00287 virtual void bindString(unsigned int param, const std::string& value, bool copy_value = true) {
00288 if (sqlite3_bind_text(m_sqlite_stmt, param+1, value.c_str(),
00289 value.size(), (copy_value ? SQLITE_TRANSIENT : SQLITE_STATIC)) != SQLITE_OK)
00290 SQLiteDatabase::throwAPIException(m_sqlite_db);
00291 }
00292
00300 virtual void bindBlob(unsigned int param, const char *value, size_t size, bool copy_value = true) {
00301 if (sqlite3_bind_blob(m_sqlite_stmt, param+1, value,
00302 size, (copy_value ? SQLITE_TRANSIENT : SQLITE_STATIC)) != SQLITE_OK)
00303 SQLiteDatabase::throwAPIException(m_sqlite_db);
00304 }
00305
00313 virtual void bindString(unsigned int param, const char *value, bool copy_value = true) {
00314 if (sqlite3_bind_text(m_sqlite_stmt, param+1, value,
00315 -1, (copy_value ? SQLITE_TRANSIENT : SQLITE_STATIC)) != SQLITE_OK)
00316 SQLiteDatabase::throwAPIException(m_sqlite_db);
00317 }
00318
00325 virtual void bindInt(unsigned int param, const boost::int32_t value) {
00326 if (sqlite3_bind_int(m_sqlite_stmt, param+1, value) != SQLITE_OK)
00327 SQLiteDatabase::throwAPIException(m_sqlite_db);
00328 }
00329
00336 virtual void bindUInt(unsigned int param, const boost::uint32_t value) {
00337 if (sqlite3_bind_int(m_sqlite_stmt, param+1, value) != SQLITE_OK)
00338 SQLiteDatabase::throwAPIException(m_sqlite_db);
00339 }
00340
00347 virtual void bindBigInt(unsigned int param, const boost::int64_t value) {
00348 if (sqlite3_bind_int64(m_sqlite_stmt, param+1, value) != SQLITE_OK)
00349 SQLiteDatabase::throwAPIException(m_sqlite_db);
00350 }
00351
00358 virtual void bindUBigInt(unsigned int param, const boost::uint64_t value) {
00359 if (sqlite3_bind_int64(m_sqlite_stmt, param+1, value) != SQLITE_OK)
00360 SQLiteDatabase::throwAPIException(m_sqlite_db);
00361 }
00362
00369 virtual void bindFloat(unsigned int param, const float value) {
00370 if (sqlite3_bind_double(m_sqlite_stmt, param+1, value) != SQLITE_OK)
00371 SQLiteDatabase::throwAPIException(m_sqlite_db);
00372 }
00373
00380 virtual void bindDouble(unsigned int param, const double value) {
00381 if (sqlite3_bind_double(m_sqlite_stmt, param+1, value) != SQLITE_OK)
00382 SQLiteDatabase::throwAPIException(m_sqlite_db);
00383 }
00384
00391 virtual void bindLongDouble(unsigned int param, const long double value) {
00392 if (sqlite3_bind_double(m_sqlite_stmt, param+1, value) != SQLITE_OK)
00393 SQLiteDatabase::throwAPIException(m_sqlite_db);
00394 }
00395
00402 virtual void bindDateTime(unsigned int param, const PionDateTime& value) {
00403
00404 char *as_string = getDateTimeString(boost::get<const PionDateTime&>(value));
00405 if (sqlite3_bind_text(m_sqlite_stmt, param+1, as_string,
00406 strlen(as_string), SQLITE_TRANSIENT) != SQLITE_OK)
00407 SQLiteDatabase::throwAPIException(m_sqlite_db);
00408 }
00409
00416 virtual void bindDate(unsigned int param, const PionDateTime& value) {
00417
00418 char *as_string = getDateString(boost::get<const PionDateTime&>(value));
00419 if (sqlite3_bind_text(m_sqlite_stmt, param+1, as_string,
00420 strlen(as_string), SQLITE_TRANSIENT) != SQLITE_OK)
00421 SQLiteDatabase::throwAPIException(m_sqlite_db);
00422 }
00423
00430 virtual void bindTime(unsigned int param, const PionDateTime& value) {
00431
00432 char *as_string = getTimeString(boost::get<const PionDateTime&>(value));
00433 if (sqlite3_bind_text(m_sqlite_stmt, param+1, as_string,
00434 strlen(as_string), SQLITE_TRANSIENT) != SQLITE_OK)
00435 SQLiteDatabase::throwAPIException(m_sqlite_db);
00436 }
00437
00439 virtual void fetchString(unsigned int param, std::string& value) {
00440 const char *ptr = (const char *)sqlite3_column_text(m_sqlite_stmt, param);
00441 if (ptr)
00442 value = ptr;
00443 else
00444 value = "";
00445 }
00446
00448 virtual void fetchBlob(unsigned int param, std::string& value) {
00449 const char *ptr = (const char *)sqlite3_column_blob(m_sqlite_stmt, param);
00450 int size = sqlite3_column_bytes(m_sqlite_stmt, param);
00451 if (ptr && size > 0)
00452 value = std::string(ptr, size);
00453 else
00454 value = "";
00455 }
00456
00458 virtual boost::int32_t fetchInt(unsigned int param) {
00459 return sqlite3_column_int(m_sqlite_stmt, param);
00460 }
00461
00463 virtual boost::uint32_t fetchUInt(unsigned int param) {
00464 return sqlite3_column_int(m_sqlite_stmt, param);
00465 }
00466
00468 virtual boost::int64_t fetchBigInt(unsigned int param) {
00469 return sqlite3_column_int64(m_sqlite_stmt, param);
00470 }
00471
00473 virtual boost::uint64_t fetchUBigInt(unsigned int param) {
00474 return sqlite3_column_int64(m_sqlite_stmt, param);
00475 }
00476
00478 virtual float fetchFloat(unsigned int param) {
00479 return sqlite3_column_double(m_sqlite_stmt, param);
00480 }
00481
00483 virtual double fetchDouble(unsigned int param) {
00484 return sqlite3_column_double(m_sqlite_stmt, param);
00485 }
00486
00488 virtual long double fetchLongDouble(unsigned int param) {
00489 return sqlite3_column_double(m_sqlite_stmt, param);
00490 }
00491
00493 virtual void fetchDateTime(unsigned int param, PionDateTime& val) {
00494
00495 const char *ptr = (const char *)sqlite3_column_text(m_sqlite_stmt, param);
00496 if (ptr) {
00497
00498 PionTimeFacet time_facet("%Y-%m-%d %H:%M:%S");
00499 val = time_facet.fromString(ptr);
00500 }
00501
00502
00503 }
00504
00506 virtual void fetchDate(unsigned int param, PionDateTime& val) {
00507
00508 const char *ptr = (const char *)sqlite3_column_text(m_sqlite_stmt, param);
00509 if (ptr) {
00510 PionTimeFacet time_facet("%Y-%m-%d");
00511 val = time_facet.fromString(ptr);
00512 }
00513 }
00514
00516 virtual void fetchTime(unsigned int param, PionDateTime& val) {
00517
00518 const char *ptr = (const char *)sqlite3_column_text(m_sqlite_stmt, param);
00519 if (ptr) {
00520 PionTimeFacet time_facet("%H:%M:%S");
00521 val = time_facet.fromString(ptr);
00522 }
00523 }
00524
00530 virtual bool run(void);
00531
00543 virtual bool runFullQuery(const pion::platform::Query::FieldMap& ins, const pion::platform::EventPtr& src,
00544 const pion::platform::Query::FieldMap& outs, pion::platform::EventPtr& dest,
00545 unsigned int limit, const boost::regex& suppress);
00546
00547 virtual bool runFullGetMore(const pion::platform::Query::FieldMap& outs, pion::platform::EventPtr& dest,
00548 unsigned int limit);
00549
00551 virtual void reset(void) { sqlite3_reset(m_sqlite_stmt); }
00552
00554 bool fetchRow(const FieldMap& field_map, pion::platform::EventPtr e);
00555
00556
00557 private:
00558
00560 sqlite3 * m_sqlite_db;
00561
00563 sqlite3_stmt * m_sqlite_stmt;
00564 };
00565
00566
00567 private:
00568
00570 static const std::string BACKUP_FILE_EXTENSION;
00571
00573 static const std::string FILENAME_ELEMENT_NAME;
00574
00575
00577 std::string m_database_name;
00578
00580 sqlite3 * m_sqlite_db;
00581
00583 char * m_error_ptr;
00584
00586 boost::uint64_t m_cache_size;
00587
00589 unsigned m_partition;
00590 };
00591
00592
00593
00594
00595 inline std::string SQLiteDatabase::getSQLiteError(void)
00596 {
00597 std::string error_str;
00598 if (m_error_ptr != NULL) {
00599 error_str = m_error_ptr;
00600 sqlite3_free(m_error_ptr);
00601 m_error_ptr = NULL;
00602 }
00603 return error_str;
00604 }
00605
00606
00607 }
00608 }
00609
00610 #endif