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