Soar Kernel  9.3.2 08-06-12
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
soar_db.h
Go to the documentation of this file.
1 /*************************************************************************
2  * PLEASE SEE THE FILE "license.txt" (INCLUDED WITH THIS SOFTWARE PACKAGE)
3  * FOR LICENSE AND COPYRIGHT INFORMATION.
4  *************************************************************************/
5 
6 /*************************************************************************
7  *
8  * file: soar_db.h
9  *
10  * =======================================================================
11  */
12 
13 #ifndef SOAR_DB_H
14 #define SOAR_DB_H
15 
16 #include <portability.h>
17 
18 #include <list>
19 #include <assert.h>
20 
21 #include "soar_module.h"
22 #include "sqlite3.h"
23 
24 // separates this functionality
25 // just for Soar modules
26 namespace soar_module
27 {
29  // Constants/Enums
31 
32  // when preparing statements with strings, read till the first zero terminator
33  #define SQLITE_PREP_STR_MAX -1
34 
35  // database connection status
37 
38  // statement status
40 
41  // statement action
43 
44  // value type
46 
47  // execution result
48  enum exec_result { row, ok, err };
49 
50 
53 
54  template <typename T>
56  {
57  protected:
59  int my_errno;
60  char *my_errmsg;
61 
62  inline void set_status( T new_status ) { my_status = new_status; }
63  inline void set_errno( int new_errno ) { my_errno = new_errno; }
64 
65  inline void set_errmsg( const char *new_msg )
66  {
67  if ( my_errmsg )
68  delete my_errmsg;
69 
70  if ( new_msg )
71  {
72  size_t my_len = strlen( new_msg );
73  my_errmsg = new char[ my_len + 1 ];
74  strcpy( my_errmsg, new_msg );
75  my_errmsg[ my_len ] = '\0';
76  }
77  }
78 
79  public:
80  status_object(): my_errno( 0 ), my_errmsg( NULL ) {}
81  virtual ~status_object()
82  {
83  set_errmsg( NULL );
84  }
85 
86  //
87 
88  inline T get_status() { return my_status; }
89  inline int get_errno() { return my_errno; }
90  inline const char *get_errmsg() { return my_errmsg; }
91  };
92 
93 
96 
97  class database: public status_object<db_status>
98  {
99  public:
101  {
103  }
104  };
105 
106 
109 
110  class statement: public status_object<statement_status>
111  {
112  protected:
113  const char *sql;
115 
116  virtual exec_result _exec() = 0;
117  virtual bool _prep() = 0;
118  virtual void _reinit() = 0;
119  virtual bool _destroy() = 0;
120 
121  public:
122  statement( const char *new_sql, timer *new_query_timer ): sql( new_sql ), query_timer( new_query_timer )
123  {
125  }
126 
127  virtual ~statement() {}
128 
129  //
130 
131  inline exec_result execute( statement_action post_action = op_none )
132  {
133  exec_result return_val = err;
134 
135  if ( get_status() == ready )
136  {
137  if ( query_timer )
138  query_timer->start();
139 
140  return_val = _exec();
141  assert( return_val != err );
142 
143  if ( query_timer )
144  query_timer->stop();
145 
146  // post-action
147  switch ( post_action )
148  {
149  case op_reinit:
150  reinitialize();
151  break;
152 
153  case op_clean:
154  clean();
155  break;
156 
157  case op_none:
158  break;
159  }
160  }
161 
162  return return_val;
163  }
164 
165  inline void prepare()
166  {
167  if ( get_status() == unprepared )
168  {
169  if ( _prep() )
170  set_status( ready );
171  }
172  }
173 
174  inline void reinitialize()
175  {
176  _reinit();
177  }
178 
179  inline void clean()
180  {
181  if ( get_status() != unprepared )
182  {
183  if ( _destroy() )
185  }
186  }
187 
188  inline void set_timer( timer *new_query_timer )
189  {
190  query_timer = new_query_timer;
191  }
192  };
193 
194 
197 
199  {
200  protected:
201  std::list<statement *> *statements;
202 
203  public:
205 
207  {
208  for ( std::list<statement *>::iterator p=statements->begin(); p!=statements->end(); p++ )
209  delete (*p);
210 
211  delete statements;
212  }
213 
214  //
215 
216  void add( statement *new_statement )
217  {
218  statements->push_back( new_statement );
219  }
220 
221  //
222 
223  void prepare()
224  {
225  for ( std::list<statement *>::iterator p=statements->begin(); p!=statements->end(); p++ )
226  {
227  (*p)->prepare();
228  assert( (*p)->get_status() == ready );
229  }
230  }
231 
232  void clean()
233  {
234  for ( std::list<statement *>::iterator p=statements->begin(); p!=statements->end(); p++ )
235  {
236  (*p)->clean();
237  assert( (*p)->get_status() == unprepared );
238  }
239  }
240  };
241 
242 
245 
246  class sqlite_database: public database
247  {
248  protected:
250 
251  public:
253  {
254  set_errno( SQLITE_OK );
255  }
256 
257  virtual ~sqlite_database() {}
258 
259  //
260 
261  inline sqlite3 *get_db() { return my_db; }
262 
263  //
264 
265  inline void connect( const char *file_name, int flags = ( SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE ) )
266  {
267  int sqlite_err = sqlite3_open_v2( file_name, &( my_db ), flags, NULL );
268 
269  if ( sqlite_err == SQLITE_OK )
270  {
272 
273  set_errno( sqlite_err );
274  set_errmsg( NULL );
275  }
276  else
277  {
278  set_status( problem );
279 
280  set_errno( sqlite_err );
282  }
283  }
284 
285  inline void disconnect()
286  {
287  if ( get_status() == connected )
288  {
289  sqlite3_close( my_db );
291  }
292  }
293 
294  //
295 
296  inline int64_t last_insert_rowid() { return static_cast<int64_t>( sqlite3_last_insert_rowid( my_db ) ); }
297  inline int64_t memory_usage() { return static_cast<int64_t>( sqlite3_memory_used() ); }
298  inline int64_t memory_highwater() { return static_cast<int64_t>( sqlite3_memory_highwater( false ) ); }
299  inline const char* lib_version() { return sqlite3_libversion(); }
300 
301  inline bool backup( const char* file_name, std::string* err )
302  {
303  sqlite3* backup_db;
304  bool return_val = false;
305 
306  err->clear();
307 
308  if ( get_status() == connected )
309  {
310  int sqlite_err = sqlite3_open_v2( file_name, &( backup_db ), ( SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE ), NULL );
311  if ( sqlite_err == SQLITE_OK )
312  {
313  sqlite3_backup* backup_h = sqlite3_backup_init( backup_db, "main", my_db, "main" );
314  if ( backup_h )
315  {
316  sqlite3_backup_step( backup_h, -1 );
317  sqlite3_backup_finish( backup_h );
318  }
319 
320  if ( sqlite3_errcode( backup_db ) == SQLITE_OK )
321  {
322  return_val = true;
323  }
324  else
325  {
326  err->assign( "Error during backup: " );
327  err->append( sqlite3_errmsg( backup_db ) );
328  }
329  }
330  else
331  {
332  err->assign( "Error opening backup file: " );
333  err->append( sqlite3_errmsg( backup_db ) );
334  }
335  sqlite3_close( backup_db );
336  }
337  else
338  {
339  err->assign( "Database is not currently connected." );
340  }
341 
342  return return_val;
343  }
344  };
345 
346 
349 
351  {
352  protected:
355 
356  inline void sqlite_err()
357  {
360  }
361 
362  virtual bool _prep()
363  {
364  const char *tail;
365  bool return_val = false;
366 
368  {
369  return_val = true;
370  }
371  else
372  {
373  sqlite_err();
374  }
375 
376  return return_val;
377  }
378 
379  virtual void _reinit()
380  {
382  }
383 
384  virtual bool _destroy()
385  {
387  my_stmt = NULL;
388 
389  return true;
390  }
391 
392  virtual exec_result _exec()
393  {
394  int sqlite_res = sqlite3_step( my_stmt );
395  exec_result return_val = err;
396 
397  if ( ( sqlite_res != SQLITE_OK ) &&
398  ( sqlite_res != SQLITE_DONE ) &&
399  ( sqlite_res != SQLITE_ROW ) )
400  {
401  sqlite_err();
402  }
403  else
404  {
405  return_val = ( ( sqlite_res == SQLITE_ROW )?( row ):( ok ) );
406  }
407 
408  return return_val;
409  }
410 
411 
412  public:
413  sqlite_statement( sqlite_database *new_db, const char *new_sql, timer *new_query_timer = NULL ): statement( new_sql, new_query_timer ), my_db( new_db ), my_stmt( NULL ) {}
414 
416  {
417  if ( my_stmt )
418  _destroy();
419  }
420 
421  //
422 
423  inline void bind_int( int param, int64_t val )
424  {
425  sqlite3_bind_int64( my_stmt, param, static_cast<sqlite3_int64>( val ) );
426  }
427 
428  inline void bind_double( int param, double val )
429  {
430  sqlite3_bind_double( my_stmt, param, val );
431  }
432 
433  inline void bind_null( int param )
434  {
435  sqlite3_bind_null( my_stmt, param );
436  }
437 
438  inline void bind_text( int param, const char *val )
439  {
441  }
442 
443  //
444 
445  inline int64_t column_int( int col )
446  {
447  return sqlite3_column_int64( my_stmt, col );
448  }
449 
450  inline double column_double( int col )
451  {
452  return sqlite3_column_double( my_stmt, col );
453  }
454 
455  inline const char *column_text( int col )
456  {
457  return reinterpret_cast<const char *>( sqlite3_column_text( my_stmt, col ) );
458  }
459 
460  inline value_type column_type( int col )
461  {
462  int col_type = sqlite3_column_type( my_stmt, col );
463  value_type return_val = null_t;
464 
465  switch ( col_type )
466  {
467  case SQLITE_INTEGER:
468  return_val = int_t;
469  break;
470 
471  case SQLITE_FLOAT:
472  return_val = double_t;
473  break;
474 
475  case SQLITE_TEXT:
476  return_val = text_t;
477  break;
478  }
479 
480  return return_val;
481  }
482  };
483 
484 
487 
489  {
490  protected:
491  std::list<const char *> *structures;
492 
494 
495  public:
496  sqlite_statement_container( sqlite_database *new_db ): statement_container(), structures( new std::list<const char *>() ), my_db( new_db ) {}
497 
499  {
500  delete structures;
501  }
502 
503  //
504 
505  inline void add_structure( const char *new_structure )
506  {
507  structures->push_back( new_structure );
508  }
509 
510  void structure()
511  {
512  sqlite_statement *temp_stmt;
513 
514  for ( std::list<const char *>::iterator p=structures->begin(); p!=structures->end(); p++ )
515  {
516  temp_stmt = new sqlite_statement( my_db, (*p) );
517 
518  temp_stmt->prepare();
519  assert( temp_stmt->get_status() == ready );
520  temp_stmt->execute();
521 
522  delete temp_stmt;
523  }
524  }
525  };
526 
527 
530 
531  class sqlite_statement_pool;
532 
534  {
535  protected:
537 
538  public:
539  pooled_sqlite_statement( sqlite_statement_pool* new_pool, sqlite_database* new_db, const char* new_sql, timer* new_query_timer = NULL ): sqlite_statement( new_db, new_sql, new_query_timer ), stmt_pool( new_pool ) {}
540 
542  {
543  return stmt_pool;
544  }
545  };
546 
548  {
549  protected:
550  #ifdef USE_MEM_POOL_ALLOCATORS
551  typedef std::list< pooled_sqlite_statement*, soar_memory_pool_allocator< pooled_sqlite_statement* > > sqlite_statement_pool_pool;
552  #else
553  typedef std::list< pooled_sqlite_statement* > sqlite_statement_pool_pool;
554  #endif
555 
557 
559  const char* my_sql;
560 
561  public:
562  sqlite_statement_pool( agent* my_agent, sqlite_database* new_db, const char* new_sql ): my_db( new_db ), my_sql( new_sql )
563  {
564  #ifdef USE_MEM_POOL_ALLOCATORS
565  statements = new sqlite_statement_pool_pool( my_agent );
566  #else
567  my_agent;
569  #endif
570  }
571 
573  {
574  for ( sqlite_statement_pool_pool::iterator it=statements->begin(); it!=statements->end(); it++ )
575  {
576  delete (*it);
577  }
578 
579  delete statements;
580  }
581 
583  {
584  stmt->reinitialize();
585  statements->push_front( stmt );
586  }
587 
588  pooled_sqlite_statement* request( timer* query_timer = NULL )
589  {
590  pooled_sqlite_statement* return_val = NULL;
591 
592  if ( statements->empty() )
593  {
594  // make new (assigns timer)
595  return_val = new pooled_sqlite_statement( this, my_db, my_sql, query_timer );
596 
597  // ready to use
598  return_val->prepare();
599  }
600  else
601  {
602  return_val = statements->front();
603  statements->pop_front();
604 
605  // assign timer
606  return_val->set_timer( query_timer );
607  }
608 
609  return return_val;
610  }
611  };
612 }
613 
614 #endif