platform/databases/SQLiteDatabase.hpp

00001 // ------------------------------------------------------------------------
00002 // Pion is a development platform for building Reactors that process Events
00003 // ------------------------------------------------------------------------
00004 // Copyright (C) 2007-2008 Atomic Labs, Inc.  (http://www.atomiclabs.com)
00005 //
00006 // Pion is free software: you can redistribute it and/or modify it under the
00007 // terms of the GNU Affero General Public License as published by the Free
00008 // Software Foundation, either version 3 of the License, or (at your option)
00009 // any later version.
00010 //
00011 // Pion is distributed in the hope that it will be useful, but WITHOUT ANY
00012 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00013 // FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for
00014 // more details.
00015 //
00016 // You should have received a copy of the GNU Affero General Public License
00017 // along with Pion.  If not, see <http://www.gnu.org/licenses/>.
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 {        // begin namespace pion
00033 namespace plugins {     // begin 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;   // SQLite has a 9 byte rowid
00122             case CACHE_PAGE_CACHE_SIZE:
00123                 return m_cache_size;
00124             case CACHE_PAGE_UTILIZATION:
00125                 return 85;  // average efficiency for index
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;   // Just to make compiler happy...
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             // store it as an iso extended string
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             // store it as an iso extended string
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             // store it as an iso extended string
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             // %Y-%m-%dT%H:%M:%S%F
00495             const char *ptr = (const char *)sqlite3_column_text(m_sqlite_stmt, param);
00496             if (ptr) {
00497 //              PionTimeFacet time_facet("%Y-%m-%dT%H:%M:%S%F");
00498                 PionTimeFacet time_facet("%Y-%m-%d %H:%M:%S");
00499                 val = time_facet.fromString(ptr);
00500             }
00501 //          val = boost::posix_time::time_from_string(reinterpret_cast<const char *>(sqlite3_column_text(m_sqlite_stmt, param)));
00502 //          val = f.fromString(reinterpret_cast<const char *>(sqlite3_column_text(m_sqlite_stmt, param)));
00503         }
00504 
00506         virtual void fetchDate(unsigned int param, PionDateTime& val) {
00507             // %Y-%m-%dT%H:%M:%S%F
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             // %Y-%m-%dT%H:%M:%S%F
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 // inline member functions for SQLiteDatabase
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 }   // end namespace plugins
00608 }   // end namespace pion
00609 
00610 #endif

Generated on Wed Apr 13 16:38:34 2011 for pion-platform by  doxygen 1.4.7