libsq3 2007.10.18
sq3_log_db.cpp
1
2#include "sq3_log_db.hpp"
3#include <iostream>
4#include <sstream>
5#include <vector>
6#include <cstdio> // vsnprint()
7#include <cstring>
8namespace sq3 {
9
10 log_db::log_db( std::string const & filename )
11 : database()
12 {
13 this->database::open(filename);
14 }
15
17 {
18 }
19
21 {
22 if( ! this->is_open() )
23 {
24 return SQLITE_ERROR;
25 }
26 std::string sql( "create table if not exists log(ts,msg TEXT)" );
27 this->execute( sql );
28 /**
29 enable temp_store=MEMORY to speed this up considably on PocketPC
30 devices writing to SD cards.
31 */
32 this->pragma( "temp_store = MEMORY" );
33 return SQLITE_OK;
34 }
35
37 {
38 return this->execute( "delete from log" );
39 }
40
41 static char const * LOG_DB_LOG_INSERT_SQL = "insert into log (ts,msg) values(strftime('%Y-%m-%d %H:%M:%f','now'),?)";
42 // "insert into log (ts,msg) values(current_timestamp,?)"
43
44 bool log_db::log( std::string const & msg )
45 {
46 if( ! this->is_open() )
47 {
48 return false;
49 }
50 if( msg.empty() ) return true;
51 statement st( *this, LOG_DB_LOG_INSERT_SQL );
52 st.bind( 1, msg );
53 int rc = st.execute();
54 return rc_is_okay( rc );
55 // In theory, if the count_changes PRAGMA is on then SQLITE_ROW will be returned from execute()
56 }
57
58 bool log_db::log(const char *format,...)
59 {
60 if( ! this->is_open() )
61 {
62 return false;
63 }
64 const int buffsz = static_cast<int>( std::max( (size_t) 2048, strlen(format) * 2 ) );
65 std::vector<char> buffer( buffsz, '\0' );
66 va_list vargs;
67 va_start ( vargs, format );
68 using namespace std;
69 /** In gcc, vsnprintf() is in the std namespace, but in MSVC it is not, so we use 'using'
70 to accomodate both cases. */
71 int size = vsnprintf(&buffer[0], buffsz, format, vargs);
72 va_end( vargs );
73 if (size > (buffsz-1))
74 {
75 // replace tail of msg with "..."
76 size = buffsz-1;
77 for( int i = buffsz-4; i < buffsz-1; ++i )
78 {
79 buffer[i] = '.';
80 }
81 }
82 buffer[size] = '\0';
83 if( size )
84 {
85 statement st( *this, LOG_DB_LOG_INSERT_SQL );
86 st.bind( 1, &buffer[0], size );
87 int rc = st.execute();
88 //std::cout << "FYI: rc from an INSERT is " << rc << '\n'; // == SQLITE_DONE
89 return SQLITE_DONE == rc;
90 }
91 return true;
92 }
93
94#undef LOG_DB_LOG_INSERT_SQL
95
96 void log_db::show_last( int count )
97 {
98 if( ! this->is_open() )
99 {
100 return;
101 }
102 std::ostream & os = std::cout;
103 os << "sq3::log_db: most recent "
104 << count << " entries:\n";
105 if( ! this->is_open() )
106 {
107 os << "ERROR: Log database is not opened!";
108 return;
109 }
110 std::ostringstream fmt;
111 if( 0 )
112 { // newest entries at the top:
113 fmt << "select /*DATETIME(ts)*/ts,msg from log "
114 << "order by ts desc, rowid desc"
115 <<" limit " << count
116 ;
117 }
118 else
119 { // in "natural order":
120 fmt << "select /*DATETIME(ts)*/ts,msg from log "
121 << "order by ts asc, rowid asc"
122 <<" limit " << count
123 ;
124 }
125 std::string sql(fmt.str());
126 statement st( *this, sql );
127 cursor r = st.get_cursor();
128 std::string buff;
129 while( SQLITE_ROW == r.step() )
130 {
131 std::string tmp;
132 r.get( 0, tmp );
133 os << tmp << ": ";
134 r.get( 1, tmp );
135 os << tmp << '\n';
136 }
137 }
138
139 bool log_db::trim( int count )
140 {
141 if( this->is_open() )
142 {
143 std::ostringstream os;
144 os << "delete from log where rowid not in (select rowid from log order by ts desc, rowid desc limit "<<count<<")";
145 std::string sql( os.str() );
146 if( SQLITE_OK == this->execute( sql.c_str() ) )
147 {
148 this->vacuum();
149 }
150 return true; // delete will fail if the db is empty, but we'll consider that to be success
151 }
152 return false;
153 }
154
155} // namespace
This type is for stepping through a db query result.
Definition: sq3.hpp:685
int step()
Uses sqlite3_step() to step through this object's data set by one step.
Definition: sq3.cpp:370
int get(int index, int &tgt)
If column index (0-based) is in bounds then this function assigns tgt to the value of the given colum...
Definition: sq3.cpp:413
Encapsulates a connection to an sqlite database.
Definition: sq3.hpp:233
bool is_open() const
Returns true if this db is opened.
Definition: sq3.cpp:563
int vacuum()
Convenience wrapper around execute("vacuum").
Definition: sq3.cpp:822
int execute(const std::string &sql)
Functionally identical to execute(char const *).
Definition: sq3.cpp:698
virtual int open(char const *, long flags=0)
Creates/opens the given db file.
Definition: sq3.cpp:591
int pragma(char const *code)
This is a convenience wrapper for execute( "pragma ..." ).
Definition: sq3.cpp:814
virtual int on_open()
Called when open() succeeds.
Definition: sq3_log_db.cpp:20
log_db()
Creates an unopened database.
bool trim(int leaveThisMany)
Deletes all entries in the log except the leaveThisMany most recent.
Definition: sq3_log_db.cpp:139
bool log(std::string const &msg)
Logs a message to the log database.
Definition: sq3_log_db.cpp:44
virtual ~log_db()
Closes this db.
Definition: sq3_log_db.cpp:16
virtual void show_last(int howMany)
Shows the last count entries using a subclass-specific method.
Definition: sq3_log_db.cpp:96
virtual int clear()
Empties the log database.
Definition: sq3_log_db.cpp:36
cursor get_cursor()
Returns a cursor object ready to step over the result set from this object.
Definition: sq3.cpp:246
int bind(int index)
Binds NULL to the given placeholder index (1-based, not 0-based!).
Definition: sq3.cpp:173
int execute()
Assumes this object's SQL statement is a single statement.
Definition: sq3.cpp:250
The sq3 namespace encapsulates an OO sqlite3 API very similar to the sqlite3x API,...
Definition: sq3.hpp:77
bool rc_is_okay(int rc)
rc_is_okay() is an easy way to check if rc is one of SQLITE_OK, SQLITE_ROW, or SQLITE_DONE.
Definition: sq3.cpp:56