CYCLUS
sqlite_back.cc
Go to the documentation of this file.
1 #include "sqlite_back.h"
2 
3 #include <iomanip>
4 #include <sstream>
5 
6 #include <boost/lexical_cast.hpp>
7 #include <boost/uuid/uuid_io.hpp>
8 #include <boost/algorithm/string.hpp>
9 #include <boost/archive/tmpdir.hpp>
10 #include <boost/archive/xml_iarchive.hpp>
11 #include <boost/archive/xml_oarchive.hpp>
12 #include <boost/serialization/base_object.hpp>
13 #include <boost/serialization/utility.hpp>
14 #include <boost/serialization/list.hpp>
15 #include <boost/serialization/set.hpp>
16 #include <boost/serialization/vector.hpp>
17 #include <boost/serialization/map.hpp>
18 #include <boost/serialization/assume_abstract.hpp>
19 
20 
21 #include "blob.h"
22 #include "datum.h"
23 #include "error.h"
24 #include "logger.h"
25 
26 namespace cyclus {
27 
28 std::vector<std::string> split(const std::string& s, char delim) {
29  std::vector<std::string> elems;
30  std::stringstream ss(s);
31  std::string item;
32  while (std::getline(ss, item, delim)) {
33  elems.push_back(item);
34  }
35  return elems;
36 }
37 
39  try {
40  Flush();
41  db_.close();
42  } catch (Error err) {
43  CLOG(LEV_ERROR) << "Error in SqliteBack destructor: " << err.what();
44  }
45 }
46 
48  path_ = path;
49  db_.open();
50 
51  db_.Execute("PRAGMA synchronous=OFF;");
52  db_.Execute("PRAGMA journal_mode=MEMORY;");
53  db_.Execute("PRAGMA temp_store=MEMORY;");
54 
55  // cache pre-existing table names
56  SqlStatement::Ptr stmt;
57  stmt = db_.Prepare("SELECT name FROM sqlite_master WHERE type='table';");
58 
59  for (int i = 0; stmt->Step(); ++i) {
60  tbl_names_.insert(stmt->GetText(0, NULL));
61  }
62 
63  if (tbl_names_.count("FieldTypes") == 0) {
64  std::string cmd = "CREATE TABLE IF NOT EXISTS FieldTypes";
65  cmd += "(TableName TEXT,Field TEXT,Type INTEGER);";
66  db_.Execute(cmd);
67  }
68 }
69 
71  db_.Execute("BEGIN TRANSACTION;");
72  try {
73  for (DatumList::iterator it = data.begin(); it != data.end(); ++it) {
74  std::string tbl = (*it)->title();
75  if (tbl_names_.count(tbl) == 0) {
76  CreateTable(*it);
77  }
78  if (stmts_.count(tbl) == 0) {
79  BuildStmt(*it);
80  }
81  WriteDatum(*it);
82  }
83  } catch (ValueError err) {
84  db_.Execute("END TRANSACTION;");
85  throw ValueError(err.what());
86  }
87  db_.Execute("END TRANSACTION;");
88  Flush();
89 }
90 
92 
93 std::list<ColumnInfo> SqliteBack::Schema(std::string table) {
94  std::list<ColumnInfo> schema;
95  QueryResult qr = GetTableInfo(table);
96  for (int i = 0; i < qr.fields.size(); ++i) {
97  ColumnInfo info = ColumnInfo(table, qr.fields[i], i, qr.types[i], std::vector<int>());
98  schema.push_back(info);
99  }
100  return schema;
101 }
102 
103 QueryResult SqliteBack::Query(std::string table, std::vector<Cond>* conds) {
104  QueryResult q = GetTableInfo(table);
105 
106  std::stringstream sql;
107  sql << "SELECT * FROM " << table;
108  if (conds != NULL) {
109  sql << " WHERE ";
110  for (int i = 0; i < conds->size(); ++i) {
111  if (i > 0) {
112  sql << " AND ";
113  }
114  Cond c = (*conds)[i];
115  sql << c.field << " " << c.op << " ?";
116  }
117  }
118  sql << ";";
119 
120  SqlStatement::Ptr stmt = db_.Prepare(sql.str());
121 
122  if (conds != NULL) {
123  for (int i = 0; i < conds->size(); ++i) {
124  boost::spirit::hold_any v = (*conds)[i].val;
125  Bind(v, Type(v), stmt, i+1);
126  }
127  }
128 
129  for (int i = 0; stmt->Step(); ++i) {
130  QueryRow r;
131  for (int j = 0; j < q.fields.size(); ++j) {
132  r.push_back(ColAsVal(stmt, j, q.types[j]));
133  }
134  q.rows.push_back(r);
135  }
136  return q;
137 }
138 
139 std::map<std::string, DbTypes> SqliteBack::ColumnTypes(std::string table) {
140  QueryResult qr = GetTableInfo(table);
141  std::map<std::string, DbTypes> rtn;
142  for (int i = 0; i < qr.fields.size(); ++i)
143  rtn[qr.fields[i]] = qr.types[i];
144  return rtn;
145 }
146 
147 std::set<std::string> SqliteBack::Tables() {
148  using std::set;
149  using std::string;
150  set<string> rtn;
151  std::string sql = "SELECT name FROM sqlite_master WHERE type='table';";
152  SqlStatement::Ptr stmt;
153  stmt = db_.Prepare(sql);
154  while (stmt->Step()) {
155  rtn.insert(stmt->GetText(0, NULL));
156  }
157  rtn.erase("FieldTypes");
158  return rtn;
159 }
160 
162  return db_;
163 }
164 
165 QueryResult SqliteBack::GetTableInfo(std::string table) {
166  std::string sql = "SELECT Field,Type FROM FieldTypes WHERE TableName = '" +
167  table + "';";
168  SqlStatement::Ptr stmt;
169  stmt = db_.Prepare(sql);
170 
171  int i = 0;
172  QueryResult info;
173  for (i = 0; stmt->Step(); ++i) {
174  info.fields.push_back(stmt->GetText(0, NULL));
175  info.types.push_back((DbTypes)stmt->GetInt(1));
176  }
177  if (i == 0) {
178  throw ValueError("Invalid table name " + table);
179  }
180  return info;
181 }
182 
184  return path_;
185 }
186 
187 void SqliteBack::BuildStmt(Datum* d) {
188  std::string name = d->title();
189  Datum::Vals vals = d->vals();
190  std::vector<DbTypes> schema;
191 
192  schema.push_back(Type(vals[0].second));
193  std::string insert = "INSERT INTO " + name + " VALUES (?";
194  for (int i = 1; i < vals.size(); ++i) {
195  schema.push_back(Type(vals[i].second));
196  insert += ", ?";
197  }
198  insert += ");";
199 
200  schemas_[name] = schema;
201  stmts_[name] = db_.Prepare(insert);
202 }
203 
204 void SqliteBack::CreateTable(Datum* d) {
205  std::string name = d->title();
206  tbl_names_.insert(name);
207 
208  Datum::Vals vals = d->vals();
209  Datum::Vals::iterator it = vals.begin();
210 
211  std::stringstream types;
212  types << "INSERT INTO FieldTypes VALUES ('"
213  << name << "','" << it->first << "','"
214  << Type(it->second) << "');";
215  db_.Execute(types.str());
216 
217  std::string cmd = "CREATE TABLE " + name + " (";
218  cmd += std::string(it->first) + " " + SqlType(it->second);
219  ++it;
220 
221  while (it != vals.end()) {
222  cmd += ", " + std::string(it->first) + " " + SqlType(it->second);
223  std::stringstream types;
224  types << "INSERT INTO FieldTypes VALUES ('"
225  << name << "','" << it->first << "','"
226  << Type(it->second) << "');";
227  db_.Execute(types.str());
228  ++it;
229  }
230 
231  cmd += ");";
232  db_.Execute(cmd);
233 }
234 
235 void SqliteBack::WriteDatum(Datum* d) {
236  Datum::Vals vals = d->vals();
237  SqlStatement::Ptr stmt = stmts_[d->title()];
238  std::vector<DbTypes> schema = schemas_[d->title()];
239 
240  for (int i = 0; i < vals.size(); ++i) {
241  boost::spirit::hold_any v = vals[i].second;
242  Bind(v, schema[i], stmt, i+1);
243  }
244 
245  stmt->Exec();
246 }
247 
248 void SqliteBack::Bind(boost::spirit::hold_any v, DbTypes type, SqlStatement::Ptr stmt,
249  int index) {
250 
251 // serializes the value v of type T and DBType D and binds it to stmt (inside
252 // a case statement.
253 // NOTE: Since we are archiving to a stringstream, the archive must be closed before
254 // the stringstream, so we put it in its own scope. This first became an issue in
255 // Boost v1.66.0. For more information, see http://boost.2283326.n4.nabble.com/the-boost-xml-serialization-to-a-stringstream-does-not-have-an-end-tag-tp2580772p2580773.html
256 #define CYCLUS_COMMA ,
257 #define CYCLUS_BINDVAL(D, T) \
258  case D: { \
259  T vect = v.cast<T>(); \
260  std::stringstream ss; \
261  { \
262  boost::archive::xml_oarchive ar(ss); \
263  ar & BOOST_SERIALIZATION_NVP(vect); \
264  } \
265  v = vect; \
266  std::string s = ss.str(); \
267  stmt->BindBlob(index, s.c_str(), s.size()); \
268  break; \
269  }
270 
271  switch (type) {
272  case INT: {
273  stmt->BindInt(index, v.cast<int>());
274  break;
275  }
276  case BOOL: {
277  stmt->BindInt(index, v.cast<bool>());
278  break;
279  }
280  case DOUBLE: {
281  stmt->BindDouble(index, v.cast<double>());
282  break;
283  }
284  case FLOAT: {
285  stmt->BindDouble(index, v.cast<float>());
286  break;
287  }
288  case BLOB: {
289  std::string s = v.cast<Blob>().str();
290  stmt->BindBlob(index, s.c_str(), s.size());
291  break;
292  }
293  case STRING: {
294  stmt->BindText(index, v.cast<std::string>().c_str());
295  break;
296  }
297  case UUID: {
298  boost::uuids::uuid ui = v.cast<boost::uuids::uuid>();
299  stmt->BindBlob(index, ui.data, 16);
300  break;
301  }
302  CYCLUS_BINDVAL(SET_INT, std::set<int>);
303  CYCLUS_BINDVAL(SET_STRING, std::set<std::string>);
304  CYCLUS_BINDVAL(LIST_INT, std::list<int>);
305  CYCLUS_BINDVAL(LIST_STRING, std::list<std::string>);
306  CYCLUS_BINDVAL(VECTOR_INT, std::vector<int>);
307  CYCLUS_BINDVAL(VECTOR_DOUBLE, std::vector<double>);
308  CYCLUS_BINDVAL(VECTOR_STRING, std::vector<std::string>);
309  CYCLUS_BINDVAL(MAP_INT_DOUBLE, std::map<int CYCLUS_COMMA double>);
310  CYCLUS_BINDVAL(MAP_INT_INT, std::map<int CYCLUS_COMMA int>);
311  CYCLUS_BINDVAL(MAP_INT_STRING, std::map<int CYCLUS_COMMA std::string>);
312  CYCLUS_BINDVAL(MAP_STRING_INT, std::map<std::string CYCLUS_COMMA int>);
313  CYCLUS_BINDVAL(MAP_STRING_DOUBLE, std::map<std::string CYCLUS_COMMA double>);
315  std::map<std::string CYCLUS_COMMA std::string>);
317  std::map<std::string CYCLUS_COMMA std::vector<double> >);
320  std::map<std::string CYCLUS_COMMA std::map<int CYCLUS_COMMA double> >);
322  std::map<std::string CYCLUS_COMMA std::pair<
323  double CYCLUS_COMMA std::map<int CYCLUS_COMMA double> > >);
325  std::map<int CYCLUS_COMMA
326  std::map<std::string CYCLUS_COMMA double> >);
329  std::map<std::string CYCLUS_COMMA
330  std::vector<std::pair<int CYCLUS_COMMA
331  std::pair<std::string CYCLUS_COMMA std::string> > > >);
332 
335  std::map<std::string CYCLUS_COMMA
336  std::pair<std::string CYCLUS_COMMA std::vector<double> > > );
337 
338  CYCLUS_BINDVAL(LIST_PAIR_INT_INT, std::list< std::pair<int CYCLUS_COMMA int> >);
339 
342  std::map<std::string CYCLUS_COMMA std::map<std::string CYCLUS_COMMA int> >);
343 
346  std::vector<std::pair<
347  std::pair<double CYCLUS_COMMA double> CYCLUS_COMMA
348  std::map<std::string CYCLUS_COMMA double> > > );
349 
352  std::map<std::pair<std::string CYCLUS_COMMA std::string> CYCLUS_COMMA int > );
353 
356  std::map<std::string CYCLUS_COMMA std::map<std::string CYCLUS_COMMA double> >);
357 
358  default: {
359  throw ValueError("attempted to retrieve unsupported sqlite backend type");
360  }
361  }
362 #undef CYCLUS_BINDVAL
363 #undef CYCLUS_COMMA
364 }
365 
366 boost::spirit::hold_any SqliteBack::ColAsVal(SqlStatement::Ptr stmt,
367  int col,
368  DbTypes type) {
369 
371 
372 // reconstructs from a serialization in stmt of type T and DbType D and
373 // store it in v.
374 #define CYCLUS_COMMA ,
375 #define CYCLUS_LOADVAL(D, T) \
376  case D: { \
377  char* data = stmt->GetText(col, NULL); \
378  std::stringstream ss; \
379  ss << data; \
380  boost::archive::xml_iarchive ar(ss); \
381  T vect; \
382  ar & BOOST_SERIALIZATION_NVP(vect); \
383  v = vect; \
384  break; \
385  }
386 
387  switch (type) {
388  case INT: {
389  v = stmt->GetInt(col);
390  break;
391  } case BOOL: {
392  v = static_cast<bool>(stmt->GetInt(col));
393  break;
394  } case DOUBLE: {
395  v = stmt->GetDouble(col);
396  break;
397  } case FLOAT: {
398  v = static_cast<float>(stmt->GetDouble(col));
399  break;
400  } case STRING: {
401  v = std::string(stmt->GetText(col, NULL));
402  break;
403  } case BLOB: {
404  int n;
405  char* s = stmt->GetText(col, &n);
406  v = Blob(std::string(s, n));
407  break;
408  } case UUID: {
409  boost::uuids::uuid u;
410  memcpy(&u, stmt->GetText(col, NULL), 16);
411  v = u;
412  break;
413  }
414  CYCLUS_LOADVAL(SET_INT, std::set<int>);
415  CYCLUS_LOADVAL(SET_STRING, std::set<std::string>);
416  CYCLUS_LOADVAL(LIST_INT, std::list<int>);
417  CYCLUS_LOADVAL(LIST_STRING, std::list<std::string>);
418  CYCLUS_LOADVAL(VECTOR_INT, std::vector<int>);
419  CYCLUS_LOADVAL(VECTOR_DOUBLE, std::vector<double>);
420  CYCLUS_LOADVAL(VECTOR_STRING, std::vector<std::string>);
421  CYCLUS_LOADVAL(MAP_INT_DOUBLE, std::map<int CYCLUS_COMMA double>);
422  CYCLUS_LOADVAL(MAP_INT_INT, std::map<int CYCLUS_COMMA int>);
423  CYCLUS_LOADVAL(MAP_INT_STRING, std::map<int CYCLUS_COMMA std::string>);
424  CYCLUS_LOADVAL(MAP_STRING_DOUBLE, std::map<std::string CYCLUS_COMMA double>);
425  CYCLUS_LOADVAL(MAP_STRING_INT, std::map<std::string CYCLUS_COMMA int>);
427  std::map<std::string CYCLUS_COMMA std::string>);
429  std::map<std::string CYCLUS_COMMA std::vector<double> >);
432  std::map<std::string CYCLUS_COMMA std::map<int CYCLUS_COMMA double> >);
434  std::map<std::string CYCLUS_COMMA std::pair<
435  double CYCLUS_COMMA std::map<int CYCLUS_COMMA double> > >);
437  std::map<int CYCLUS_COMMA
438  std::map<std::string CYCLUS_COMMA double> >);
441  std::map<std::string CYCLUS_COMMA
442  std::vector<std::pair<int CYCLUS_COMMA
443  std::pair<std::string CYCLUS_COMMA std::string> > > >);
444 
447  std::map<std::string CYCLUS_COMMA
448  std::pair<std::string CYCLUS_COMMA std::vector<double> > > );
449 
450  CYCLUS_LOADVAL(LIST_PAIR_INT_INT, std::list< std::pair<int CYCLUS_COMMA int> >);
451 
454  std::map<std::string CYCLUS_COMMA std::map<std::string CYCLUS_COMMA int> >);
455 
458  std::vector<std::pair<
459  std::pair<double CYCLUS_COMMA double> CYCLUS_COMMA
460  std::map<std::string CYCLUS_COMMA double> > > );
461 
464  std::map<std::pair<std::string CYCLUS_COMMA std::string> CYCLUS_COMMA int > );
465 
468  std::map<std::string CYCLUS_COMMA std::map<std::string CYCLUS_COMMA double> >);
469 
470  default: {
471  throw ValueError("Attempted to retrieve unsupported backend type");
472  }}
473 
474 #undef CYCLUS_LOADVAL
475 #undef CYCLUS_COMMA
476 
477  return v;
478 }
479 
480 std::string SqliteBack::SqlType(boost::spirit::hold_any v) {
481  switch (Type(v)) {
482  case INT: // fallthrough
483  case BOOL:
484  return "INTEGER";
485  case DOUBLE: // fallthrough
486  case FLOAT:
487  return "REAL";
488  case STRING:
489  return "TEXT";
490  case BLOB: // fallthrough
491  case UUID: // fallthrough
492  default: // all templated types
493  return "BLOB";
494  }
495 }
496 
497 struct compare {
498  bool operator()(const std::type_info* a, const std::type_info* b) const {
499  return a->before(*b);
500  }
501 };
502 
503 static std::map<const std::type_info*, DbTypes, compare> type_map;
504 
505 DbTypes SqliteBack::Type(boost::spirit::hold_any v) {
506  if (type_map.size() == 0) {
507  type_map[&typeid(int)] = INT;
508  type_map[&typeid(double)] = DOUBLE;
509  type_map[&typeid(float)] = FLOAT;
510  type_map[&typeid(bool)] = BOOL;
511  type_map[&typeid(Blob)] = BLOB;
512  type_map[&typeid(boost::uuids::uuid)] = UUID;
513  type_map[&typeid(std::string)] = STRING;
514  type_map[&typeid(std::set<int>)] = SET_INT;
515  type_map[&typeid(std::set<std::string>)] = SET_STRING;
516  type_map[&typeid(std::vector<int>)] = VECTOR_INT;
517  type_map[&typeid(std::vector<double>)] = VECTOR_DOUBLE;
518  type_map[&typeid(std::vector<std::string>)] = VECTOR_STRING;
519  type_map[&typeid(std::list<int>)] = LIST_INT;
520  type_map[&typeid(std::list<std::string>)] = LIST_STRING;
521  type_map[&typeid(std::map<int, int>)] = MAP_INT_INT;
522  type_map[&typeid(std::map<int, double>)] = MAP_INT_DOUBLE;
523  type_map[&typeid(std::map<int, std::string>)] = MAP_INT_STRING;
524  type_map[&typeid(std::map<std::string, int>)] = MAP_STRING_INT;
525  type_map[&typeid(std::map<std::string, double>)] = MAP_STRING_DOUBLE;
526  type_map[&typeid(std::map<std::string, std::string>)] = MAP_STRING_STRING;
527  type_map[&typeid(std::map<std::string, std::vector<double> >)] =
529  type_map[&typeid(std::map<std::string, std::map<int, double> >)] =
531  type_map[&typeid(std::map<std::string,
532  std::pair<double, std::map<int, double> > >)] =
534  type_map[&typeid(std::map<int, std::map<std::string, double> >)] =
536  type_map[&typeid(
537  std::map<std::string,
538  std::vector<std::pair<int, std::pair<std::string,
539  std::string> > > >)] =
541 
542  type_map[&typeid(
543  std::map<std::string,
544  std::pair<std::string,
545  std::vector<double> > >)] =
547 
548  type_map[&typeid(std::map<std::string, std::map<std::string,int> >)] =
550 
551  type_map[&typeid(std::list<std::pair<int, int> >)] = LIST_PAIR_INT_INT;
552 
553  type_map[&typeid(
554  std::vector<std::pair<std::pair<double, double>,
555  std::map<std::string, double> > > )] =
557 
558  type_map[&typeid(
559  std::map<std::pair<std::string, std::string>, int > )] =
561 
562  type_map[&typeid(std::map<std::string, std::map<std::string,double> >)] =
564  }
565 
566  const std::type_info* ti = &v.type();
567  if (type_map.count(ti) == 0) {
568  throw ValueError(std::string("unsupported backend type ") + ti->name());
569  }
570  return type_map[ti];
571 }
572 
573 } // namespace cyclus
const Vals & vals()
Returns a vector of all field-value pairs that have been added to this datum.
Definition: datum.cc:56
std::string title()
Returns the datum&#39;s title as specified during the datum&#39;s creation.
Definition: datum.cc:52
std::string op
One of: "<", ">", "<=", ">=", "==", "!=".
double b(int nuc)
Computes the scattering length [cm] from the coherent and incoherent components.
Definition: pyne.cc:11180
A generic mechanism to manually manage exceptions.
Definition: error.h:12
Meta data and results of a query.
boost::detail::sp_typeinfo const & type() const
Definition: any.hpp:303
An abstraction over the Sqlite native C interface to simplify database creation and data insertion...
Definition: sqlite_db.h:77
#define CYCLUS_LOADVAL(D, T)
For values that are too big, too small, etc.
Definition: error.h:41
std::string Name()
Returns a unique name for this backend.
Definition: sqlite_back.cc:183
std::string name(int nuc)
Definition: pyne.cc:2940
SqlStatement::Ptr Prepare(std::string sql)
Creates a sqlite prepared statement for the given sql.
Definition: sqlite_db.cc:133
DbTypes
This is the master list of all supported database types.
Definition: query_backend.h:31
def memcpy(dest, src, size)
virtual void Notify(DatumList data)
Writes Datum objects immediately to the database as a single transaction.
Definition: sqlite_back.cc:70
#define CLOG(level)
Definition: logger.h:39
static std::map< const std::type_info *, DbTypes, compare > type_map
Definition: sqlite_back.cc:503
void open()
Opens the sqlite database by either opening/creating a file (default) or creating/overwriting a file ...
Definition: sqlite_db.cc:108
virtual QueryResult Query(std::string table, std::vector< Cond > *conds)
Return a set of rows from the specificed table that match all given conditions.
Definition: sqlite_back.cc:103
SqliteBack(std::string path)
Creates a new sqlite backend that will write to the database file specified by path.
Definition: sqlite_back.cc:47
Used to specify and send a collection of key-value pairs to the Recorder for recording.
Definition: datum.h:15
std::vector< boost::spirit::hold_any > QueryRow
std::vector< std::string > fields
names of each field returned by a query
virtual std::set< std::string > Tables()
Return a set of all table names currently in the database.
Definition: sqlite_back.cc:147
std::vector< Entry > Vals
Definition: datum.h:20
void Flush()
Executes all pending commands.
Definition: sqlite_back.cc:91
bool operator()(const std::type_info *a, const std::type_info *b) const
Definition: sqlite_back.cc:498
std::vector< DbTypes > types
types of each field returned by a query.
std::string field
table column name
boost::shared_ptr< SqlStatement > Ptr
Definition: sqlite_db.h:25
Code providing rudimentary logging capability for the Cyclus core.
taken directly from OsiSolverInterface.cpp on 2/17/14 from https://projects.coin-or.org/Osi/browser/trunk.
Definition: agent.cc:14
A type to represent variable-length array of bytes for dumping to a cyclus output database...
Definition: blob.h:9
std::vector< QueryRow > rows
ordered results of a query
#define CYCLUS_COMMA
Represents a condition used to filter rows returned by a query.
void close()
Finishes any incomplete operations and closes the database.
Definition: sqlite_db.cc:99
virtual const char * what() const
Returns the error message associated with this Error.
Definition: error.cc:9
T const & cast() const
Definition: any.hpp:309
#define CYCLUS_BINDVAL(D, T)
std::vector< Datum * > DatumList
Definition: rec_backend.h:12
Use for errors that require agent code or input file modification (use extremely sparingly) ...
Definition: logger.h:51
virtual std::map< std::string, DbTypes > ColumnTypes(std::string table)
Return a map of column names of the specified table to the associated database type.
Definition: sqlite_back.cc:139
virtual ~SqliteBack()
Definition: sqlite_back.cc:38
SqliteDb & db()
Returns the underlying sqlite database.
Definition: sqlite_back.cc:161
Represents column information.
void Execute(std::string cmd)
Execute an SQL command.
Definition: sqlite_db.cc:139
std::vector< std::string > split(const std::string &s, char delim)
Definition: sqlite_back.cc:28