Botan  2.1.0
Crypto and TLS for C++11
sqlite3.cpp
Go to the documentation of this file.
1 /*
2 * SQLite wrapper
3 * (C) 2012 Jack Lloyd
4 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7 
8 #include <botan/sqlite3.h>
9 #include <botan/exceptn.h>
10 #include <sqlite3.h>
11 
12 namespace Botan {
13 
14 Sqlite3_Database::Sqlite3_Database(const std::string& db_filename)
15  {
16  int rc = ::sqlite3_open(db_filename.c_str(), &m_db);
17 
18  if(rc)
19  {
20  const std::string err_msg = ::sqlite3_errmsg(m_db);
21  ::sqlite3_close(m_db);
22  m_db = nullptr;
23  throw SQL_DB_Error("sqlite3_open failed - " + err_msg);
24  }
25  }
26 
28  {
29  if(m_db)
30  ::sqlite3_close(m_db);
31  m_db = nullptr;
32  }
33 
34 std::shared_ptr<SQL_Database::Statement> Sqlite3_Database::new_statement(const std::string& base_sql) const
35  {
36  return std::make_shared<Sqlite3_Statement>(m_db, base_sql);
37  }
38 
39 size_t Sqlite3_Database::row_count(const std::string& table_name)
40  {
41  auto stmt = new_statement("select count(*) from " + table_name);
42 
43  if(stmt->step())
44  return stmt->get_size_t(0);
45  else
46  throw SQL_DB_Error("Querying size of table " + table_name + " failed");
47  }
48 
49 void Sqlite3_Database::create_table(const std::string& table_schema)
50  {
51  char* errmsg = nullptr;
52  int rc = ::sqlite3_exec(m_db, table_schema.c_str(), nullptr, nullptr, &errmsg);
53 
54  if(rc != SQLITE_OK)
55  {
56  const std::string err_msg = errmsg;
57  ::sqlite3_free(errmsg);
58  ::sqlite3_close(m_db);
59  m_db = nullptr;
60  throw SQL_DB_Error("sqlite3_exec for table failed - " + err_msg);
61  }
62  }
63 
64 Sqlite3_Database::Sqlite3_Statement::Sqlite3_Statement(sqlite3* db, const std::string& base_sql)
65  {
66  int rc = ::sqlite3_prepare_v2(db, base_sql.c_str(), -1, &m_stmt, nullptr);
67 
68  if(rc != SQLITE_OK)
69  throw SQL_DB_Error("sqlite3_prepare failed " + base_sql +
70  ", code " + std::to_string(rc));
71  }
72 
73 void Sqlite3_Database::Sqlite3_Statement::bind(int column, const std::string& val)
74  {
75  int rc = ::sqlite3_bind_text(m_stmt, column, val.c_str(), -1, SQLITE_TRANSIENT);
76  if(rc != SQLITE_OK)
77  throw SQL_DB_Error("sqlite3_bind_text failed, code " + std::to_string(rc));
78  }
79 
80 void Sqlite3_Database::Sqlite3_Statement::bind(int column, size_t val)
81  {
82  if(val != static_cast<size_t>(static_cast<int>(val))) // is this legit?
83  throw SQL_DB_Error("sqlite3 cannot store " + std::to_string(val) + " without truncation");
84  int rc = ::sqlite3_bind_int(m_stmt, column, val);
85  if(rc != SQLITE_OK)
86  throw SQL_DB_Error("sqlite3_bind_int failed, code " + std::to_string(rc));
87  }
88 
89 void Sqlite3_Database::Sqlite3_Statement::bind(int column, std::chrono::system_clock::time_point time)
90  {
91  const int timeval = std::chrono::duration_cast<std::chrono::seconds>(time.time_since_epoch()).count();
92  bind(column, timeval);
93  }
94 
95 void Sqlite3_Database::Sqlite3_Statement::bind(int column, const std::vector<uint8_t>& val)
96  {
97  int rc = ::sqlite3_bind_blob(m_stmt, column, val.data(), val.size(), SQLITE_TRANSIENT);
98  if(rc != SQLITE_OK)
99  throw SQL_DB_Error("sqlite3_bind_text failed, code " + std::to_string(rc));
100  }
101 
102 void Sqlite3_Database::Sqlite3_Statement::bind(int column, const uint8_t* p, size_t len)
103  {
104  int rc = ::sqlite3_bind_blob(m_stmt, column, p, len, SQLITE_TRANSIENT);
105  if(rc != SQLITE_OK)
106  throw SQL_DB_Error("sqlite3_bind_text failed, code " + std::to_string(rc));
107  }
108 
109 std::pair<const uint8_t*, size_t> Sqlite3_Database::Sqlite3_Statement::get_blob(int column)
110  {
111  BOTAN_ASSERT(::sqlite3_column_type(m_stmt, 0) == SQLITE_BLOB,
112  "Return value is a blob");
113 
114  const void* session_blob = ::sqlite3_column_blob(m_stmt, column);
115  const int session_blob_size = ::sqlite3_column_bytes(m_stmt, column);
116 
117  BOTAN_ASSERT(session_blob_size >= 0, "Blob size is non-negative");
118 
119  return std::make_pair(static_cast<const uint8_t*>(session_blob),
120  static_cast<size_t>(session_blob_size));
121  }
122 
123 size_t Sqlite3_Database::Sqlite3_Statement::get_size_t(int column)
124  {
125  BOTAN_ASSERT(::sqlite3_column_type(m_stmt, column) == SQLITE_INTEGER,
126  "Return count is an integer");
127 
128  const int sessions_int = ::sqlite3_column_int(m_stmt, column);
129 
130  BOTAN_ASSERT(sessions_int >= 0, "Expected size_t is non-negative");
131 
132  return static_cast<size_t>(sessions_int);
133  }
134 
135 size_t Sqlite3_Database::Sqlite3_Statement::spin()
136  {
137  size_t steps = 0;
138  while(step())
139  {
140  ++steps;
141  }
142 
143  return steps;
144  }
145 
146 bool Sqlite3_Database::Sqlite3_Statement::step()
147  {
148  return (::sqlite3_step(m_stmt) == SQLITE_ROW);
149  }
150 
151 Sqlite3_Database::Sqlite3_Statement::~Sqlite3_Statement()
152  {
153  ::sqlite3_finalize(m_stmt);
154  }
155 
156 }
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:47
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:27
Definition: alg_id.cpp:13
void create_table(const std::string &table_schema) override
Definition: sqlite3.cpp:49
Sqlite3_Database(const std::string &file)
Definition: sqlite3.cpp:14
std::shared_ptr< Statement > new_statement(const std::string &sql) const override
Definition: sqlite3.cpp:34
size_t row_count(const std::string &table_name) override
Definition: sqlite3.cpp:39