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>
8 namespace 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
Encapsulates a connection to an sqlite database.
Definition: sq3.hpp:232
virtual int clear()
Empties the log database.
Definition: sq3_log_db.cpp:36
int execute(const std::string &sql)
Functionally identical to execute(char const *).
Definition: sq3.cpp:698
int bind(int index)
Binds NULL to the given placeholder index (1-based, not 0-based!).
Definition: sq3.cpp:173
log_db()
Creates an unopened database.
int vacuum()
Convenience wrapper around execute("vacuum").
Definition: sq3.cpp:822
virtual ~log_db()
Closes this db.
Definition: sq3_log_db.cpp:16
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
bool log(std::string const &msg)
Logs a message to the log database.
Definition: sq3_log_db.cpp:44
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
virtual void show_last(int howMany)
Shows the last count entries using a subclass-specific method.
Definition: sq3_log_db.cpp:96
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
bool trim(int leaveThisMany)
Deletes all entries in the log except the leaveThisMany most recent.
Definition: sq3_log_db.cpp:139
bool is_open() const
Returns true if this db is opened.
Definition: sq3.cpp:563
This type is for stepping through a db query result.
Definition: sq3.hpp:684