libsq3 2007.10.18
|
00001 00002 #include "sq3_log_db.hpp" 00003 #include <iostream> 00004 #include <sstream> 00005 #include <vector> 00006 #include <cstdio> // vsnprint() 00007 #include <cstring> 00008 namespace sq3 { 00009 00010 log_db::log_db( std::string const & filename ) 00011 : database() 00012 { 00013 this->database::open(filename); 00014 } 00015 00016 log_db::~log_db() 00017 { 00018 } 00019 00020 int log_db::on_open() 00021 { 00022 if( ! this->is_open() ) 00023 { 00024 return SQLITE_ERROR; 00025 } 00026 std::string sql( "create table if not exists log(ts,msg TEXT)" ); 00027 this->execute( sql ); 00028 /** 00029 enable temp_store=MEMORY to speed this up considably on PocketPC 00030 devices writing to SD cards. 00031 */ 00032 this->pragma( "temp_store = MEMORY" ); 00033 return SQLITE_OK; 00034 } 00035 00036 int log_db::clear() 00037 { 00038 return this->execute( "delete from log" ); 00039 } 00040 00041 static char const * LOG_DB_LOG_INSERT_SQL = "insert into log (ts,msg) values(strftime('%Y-%m-%d %H:%M:%f','now'),?)"; 00042 // "insert into log (ts,msg) values(current_timestamp,?)" 00043 00044 bool log_db::log( std::string const & msg ) 00045 { 00046 if( ! this->is_open() ) 00047 { 00048 return false; 00049 } 00050 if( msg.empty() ) return true; 00051 statement st( *this, LOG_DB_LOG_INSERT_SQL ); 00052 st.bind( 1, msg ); 00053 int rc = st.execute(); 00054 return rc_is_okay( rc ); 00055 // In theory, if the count_changes PRAGMA is on then SQLITE_ROW will be returned from execute() 00056 } 00057 00058 bool log_db::log(const char *format,...) 00059 { 00060 if( ! this->is_open() ) 00061 { 00062 return false; 00063 } 00064 const int buffsz = static_cast<int>( std::max( (size_t) 2048, strlen(format) * 2 ) ); 00065 std::vector<char> buffer( buffsz, '\0' ); 00066 va_list vargs; 00067 va_start ( vargs, format ); 00068 using namespace std; 00069 /** In gcc, vsnprintf() is in the std namespace, but in MSVC it is not, so we use 'using' 00070 to accomodate both cases. */ 00071 int size = vsnprintf(&buffer[0], buffsz, format, vargs); 00072 va_end( vargs ); 00073 if (size > (buffsz-1)) 00074 { 00075 // replace tail of msg with "..." 00076 size = buffsz-1; 00077 for( int i = buffsz-4; i < buffsz-1; ++i ) 00078 { 00079 buffer[i] = '.'; 00080 } 00081 } 00082 buffer[size] = '\0'; 00083 if( size ) 00084 { 00085 statement st( *this, LOG_DB_LOG_INSERT_SQL ); 00086 st.bind( 1, &buffer[0], size ); 00087 int rc = st.execute(); 00088 //std::cout << "FYI: rc from an INSERT is " << rc << '\n'; // == SQLITE_DONE 00089 return SQLITE_DONE == rc; 00090 } 00091 return true; 00092 } 00093 00094 #undef LOG_DB_LOG_INSERT_SQL 00095 00096 void log_db::show_last( int count ) 00097 { 00098 if( ! this->is_open() ) 00099 { 00100 return; 00101 } 00102 std::ostream & os = std::cout; 00103 os << "sq3::log_db: most recent " 00104 << count << " entries:\n"; 00105 if( ! this->is_open() ) 00106 { 00107 os << "ERROR: Log database is not opened!"; 00108 return; 00109 } 00110 std::ostringstream fmt; 00111 if( 0 ) 00112 { // newest entries at the top: 00113 fmt << "select /*DATETIME(ts)*/ts,msg from log " 00114 << "order by ts desc, rowid desc" 00115 <<" limit " << count 00116 ; 00117 } 00118 else 00119 { // in "natural order": 00120 fmt << "select /*DATETIME(ts)*/ts,msg from log " 00121 << "order by ts asc, rowid asc" 00122 <<" limit " << count 00123 ; 00124 } 00125 std::string sql(fmt.str()); 00126 statement st( *this, sql ); 00127 cursor r = st.get_cursor(); 00128 std::string buff; 00129 while( SQLITE_ROW == r.step() ) 00130 { 00131 std::string tmp; 00132 r.get( 0, tmp ); 00133 os << tmp << ": "; 00134 r.get( 1, tmp ); 00135 os << tmp << '\n'; 00136 } 00137 } 00138 00139 bool log_db::trim( int count ) 00140 { 00141 if( this->is_open() ) 00142 { 00143 std::ostringstream os; 00144 os << "delete from log where rowid not in (select rowid from log order by ts desc, rowid desc limit "<<count<<")"; 00145 std::string sql( os.str() ); 00146 if( SQLITE_OK == this->execute( sql.c_str() ) ) 00147 { 00148 this->vacuum(); 00149 } 00150 return true; // delete will fail if the db is empty, but we'll consider that to be success 00151 } 00152 return false; 00153 } 00154 00155 } // namespace