• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 33587216365

01 Sep 2026 10:01PM UTC coverage: 89.704% (-2.4%) from 92.056%
33587216365

push

github

web-flow
Merge pull request #5897 from randombit/jack/unused-includes

Remove unused header includes

123687 of 137883 relevant lines covered (89.7%)

9413861.3 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.74
/src/lib/utils/sqlite3/sqlite3.cpp
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

10
#include <botan/mem_ops.h>
11
#include <botan/internal/fmt.h>
12
#include <botan/internal/int_utils.h>
13
#include <sqlite3.h>
14

15
namespace Botan {
16

17
Sqlite3_Database::Sqlite3_Database(std::string_view db_filename, std::optional<int> sqlite_open_flags) {
136✔
18
   // SQLITE_OPEN_FULLMUTEX ensures that the database object can be used
19
   // concurrently from multiple threads.
20
   const int open_flags =
136✔
21
      sqlite_open_flags.value_or(SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX);
136✔
22
   sqlite3* db = nullptr;
136✔
23
   const int rc = ::sqlite3_open_v2(std::string(db_filename).c_str(), &db, open_flags, nullptr);
272✔
24

25
   if(rc != 0) [[unlikely]] {
136✔
26
      const std::string err_msg = (db != nullptr) ? ::sqlite3_errmsg(db) : "unknown error";
×
27
      ::sqlite3_close_v2(db);
×
28
      throw SQL_DB_Error("sqlite3_open failed - " + err_msg);
×
29
   }
×
30

31
   m_db = std::shared_ptr<sqlite3>(db, [](sqlite3* p) noexcept { ::sqlite3_close_v2(p); });
408✔
32
}
136✔
33

34
Sqlite3_Database::~Sqlite3_Database() = default;
136✔
35

36
std::shared_ptr<SQL_Database::Statement> Sqlite3_Database::new_statement(std::string_view base_sql) const {
1,411✔
37
   return std::make_shared<Sqlite3_Statement>(m_db, base_sql);
1,411✔
38
}
39

40
std::shared_ptr<SQL_Database::Statement> Sqlite3_Database::upsert(
273✔
41
   std::string_view table, std::initializer_list<std::string_view> columns) const {
42
   BOTAN_ARG_CHECK(columns.size() > 0, "upsert requires at least one column");
273✔
43

44
   std::string sql = "INSERT OR REPLACE INTO ";
273✔
45
   sql += table;
273✔
46
   sql += " (";
273✔
47
   bool first = true;
273✔
48
   for(const auto& col : columns) {
1,809✔
49
      if(!first) {
1,536✔
50
         sql += ", ";
1,263✔
51
      }
52
      sql += col;
1,536✔
53
      first = false;
1,536✔
54
   }
55
   sql += ") VALUES (";
273✔
56
   for(size_t i = 1; i <= columns.size(); ++i) {
1,809✔
57
      if(i > 1) {
1,536✔
58
         sql += ", ";
1,263✔
59
      }
60
      sql += fmt("?{}", i);
3,072✔
61
   }
62
   sql += ")";
273✔
63

64
   return new_statement(sql);
273✔
65
}
273✔
66

67
size_t Sqlite3_Database::row_count(std::string_view table_name) {
124✔
68
   auto stmt = new_statement(fmt("select count(*) from {}", table_name));
247✔
69

70
   if(stmt->step()) {
1✔
71
      return stmt->get_size_t(0);
1✔
72
   } else {
73
      throw SQL_DB_Error(fmt("Querying size of table '{}' failed", table_name));
×
74
   }
75
}
1✔
76

77
void Sqlite3_Database::create_table(const Table_Schema& schema) {
269✔
78
   BOTAN_ARG_CHECK(!schema.name().empty(), "create_table requires a table name");
269✔
79
   BOTAN_ARG_CHECK(!schema.columns().empty(), "create_table requires at least one column");
269✔
80

81
   std::string sql = "CREATE TABLE ";
269✔
82
   if(schema.is_if_not_exists()) {
269✔
83
      sql += "IF NOT EXISTS ";
21✔
84
   }
85
   sql += schema.name();
269✔
86
   sql += " (";
269✔
87
   bool first = true;
269✔
88
   for(const auto& col : schema.columns()) {
1,691✔
89
      if(!first) {
1,422✔
90
         sql += ", ";
1,153✔
91
      }
92
      sql += col.name();
1,422✔
93
      sql += ' ';
1,422✔
94
      switch(col.type()) {
1,422✔
95
         case Column_Type::Blob:
404✔
96
            sql += "BLOB";
404✔
97
            break;
98
         case Column_Type::String:
390✔
99
            sql += "TEXT";
390✔
100
            break;
101
         case Column_Type::Integer:
628✔
102
            sql += "INTEGER";
628✔
103
            break;
104
      }
105
      if(col.is_primary_key()) {
1,422✔
106
         sql += " PRIMARY KEY";
145✔
107
      }
108
      if(col.is_unique()) {
1,422✔
109
         sql += " UNIQUE";
×
110
      }
111
      if(col.is_not_null()) {
1,422✔
112
         sql += " NOT NULL";
756✔
113
      }
114
      first = false;
1,422✔
115
   }
116
   sql += ")";
269✔
117

118
   char* errmsg = nullptr;
269✔
119
   const int rc = ::sqlite3_exec(m_db.get(), sql.c_str(), nullptr, nullptr, &errmsg);
269✔
120

121
   if(rc != SQLITE_OK) {
269✔
122
      const std::string err_msg = (errmsg != nullptr) ? errmsg : "unknown error";
×
123
      ::sqlite3_free(errmsg);
×
124
      throw SQL_DB_Error("sqlite3_exec for create_table failed - " + err_msg, rc);
×
125
   }
×
126
}
269✔
127

128
size_t Sqlite3_Database::rows_changed_by_last_statement() {
32✔
129
   const auto result = ::sqlite3_changes64(m_db.get());
32✔
130
   BOTAN_ASSERT_NOMSG(result >= 0);
32✔
131
   return static_cast<size_t>(result);
32✔
132
}
133

134
bool Sqlite3_Database::is_threadsafe() const {
412✔
135
   // sqlite3_db_mutex() returns the connection's mutex if the connection is in
136
   // serialized mode, and nullptr otherwise. This reflects both the compile-time
137
   // SQLITE_THREADSAFE setting and the per-connection SQLITE_OPEN_(FULL|NO)MUTEX
138
   // open flags actually used.
139
   //
140
   // https://www.sqlite.org/c3ref/db_mutex.html
141
   return ::sqlite3_db_mutex(m_db.get()) != nullptr;
412✔
142
}
143

144
Sqlite3_Database::Sqlite3_Statement::Sqlite3_Statement(std::shared_ptr<sqlite3> db, std::string_view base_sql) :
1,411✔
145
      m_db(std::move(db)), m_stmt{} {
1,411✔
146
   const int rc =
1,411✔
147
      ::sqlite3_prepare_v2(m_db.get(), base_sql.data(), static_cast<int>(base_sql.size()), &m_stmt, nullptr);
1,411✔
148

149
   if(rc != SQLITE_OK) {
1,411✔
150
      throw SQL_DB_Error(fmt("sqlite3_prepare failed on '{}' with err {}", base_sql, rc), rc);
124✔
151
   }
152
}
1,411✔
153

154
void Sqlite3_Database::Sqlite3_Statement::bind(int column, std::string_view val) {
882✔
155
   if(val.data() == nullptr) {
882✔
156
      bind_null(column);
×
157
      return;
×
158
   }
159
   const int rc = ::sqlite3_bind_text64(m_stmt, column, val.data(), val.size(), SQLITE_TRANSIENT, SQLITE_UTF8);
882✔
160
   if(rc != SQLITE_OK) {
882✔
161
      throw SQL_DB_Error("sqlite3_bind_text failed", rc);
×
162
   }
163
}
164

165
void Sqlite3_Database::Sqlite3_Statement::bind(int column, size_t val) {
1,249✔
166
   const int rc = ::sqlite3_bind_int64(m_stmt, column, val);
1,249✔
167
   if(rc != SQLITE_OK) {
1,249✔
168
      throw SQL_DB_Error("sqlite3_bind_int failed", rc);
×
169
   }
170
}
1,249✔
171

172
void Sqlite3_Database::Sqlite3_Statement::bind(int column, std::chrono::system_clock::time_point time) {
225✔
173
   const uint64_t timeval = std::chrono::duration_cast<std::chrono::seconds>(time.time_since_epoch()).count();
225✔
174
   bind(column, static_cast<size_t>(timeval));
225✔
175
}
225✔
176

177
void Sqlite3_Database::Sqlite3_Statement::bind(int column, const std::vector<uint8_t>& val) {
764✔
178
   bind(column, val.data(), val.size());
764✔
179
}
764✔
180

181
void Sqlite3_Database::Sqlite3_Statement::bind(int column, const uint8_t* p, size_t len) {
770✔
182
   if(p == nullptr) {
770✔
183
      bind_null(column);
212✔
184
      return;
212✔
185
   }
186
   const int rc = ::sqlite3_bind_blob64(m_stmt, column, p, len, SQLITE_TRANSIENT);
558✔
187
   if(rc != SQLITE_OK) {
558✔
188
      throw SQL_DB_Error("sqlite3_bind_blob failed", rc);
×
189
   }
190
}
191

192
void Sqlite3_Database::Sqlite3_Statement::bind_null(int column) {
215✔
193
   const int rc = ::sqlite3_bind_null(m_stmt, column);
215✔
194
   if(rc != SQLITE_OK) {
215✔
195
      throw SQL_DB_Error("sqlite3_bind_null failed", rc);
×
196
   }
197
}
215✔
198

199
std::span<const uint8_t> Sqlite3_Database::Sqlite3_Statement::get_blob(int column) {
252✔
200
   const auto column_type = ::sqlite3_column_type(m_stmt, column);
252✔
201
   if(column_type == SQLITE_NULL) {
252✔
202
      return {};
41✔
203
   }
204

205
   BOTAN_ASSERT(column_type == SQLITE_BLOB, "Return value is a blob");
211✔
206

207
   const void* session_blob = ::sqlite3_column_blob(m_stmt, column);
211✔
208
   const int session_blob_size = ::sqlite3_column_bytes(m_stmt, column);
211✔
209

210
   BOTAN_ASSERT(session_blob_size >= 0, "Blob size is non-negative");
211✔
211

212
   return {static_cast<const uint8_t*>(session_blob), static_cast<size_t>(session_blob_size)};
211✔
213
}
214

215
std::optional<std::string> Sqlite3_Database::Sqlite3_Statement::get_str(int column) {
73✔
216
   const auto column_type = ::sqlite3_column_type(m_stmt, column);
73✔
217
   if(column_type == SQLITE_NULL) {
73✔
218
      return std::nullopt;
×
219
   }
220

221
   BOTAN_ASSERT(column_type == SQLITE_TEXT, "Return value is text");
73✔
222

223
   const unsigned char* str = ::sqlite3_column_text(m_stmt, column);
73✔
224
   const int len = ::sqlite3_column_bytes(m_stmt, column);
73✔
225
   BOTAN_ASSERT(len >= 0, "Text length is non-negative");
73✔
226

227
   return std::string(cast_uint8_ptr_to_char(str), static_cast<size_t>(len));
146✔
228
}
229

230
size_t Sqlite3_Database::Sqlite3_Statement::get_size_t(int column) {
6✔
231
   BOTAN_ASSERT(::sqlite3_column_type(m_stmt, column) == SQLITE_INTEGER, "Return count is an integer");
6✔
232

233
   return checked_cast_to<size_t>(::sqlite3_column_int64(m_stmt, column));
6✔
234
}
235

236
size_t Sqlite3_Database::Sqlite3_Statement::spin() {
1,021✔
237
   size_t steps = 0;
1,021✔
238
   while(step()) {
1,021✔
239
      ++steps;
×
240
   }
241

242
   return steps;
1,021✔
243
}
244

245
bool Sqlite3_Database::Sqlite3_Statement::step() {
1,404✔
246
   const int rc = ::sqlite3_step(m_stmt);
1,404✔
247
   if(rc == SQLITE_ROW) {
1,404✔
248
      return true;
249
   }
250
   if(rc == SQLITE_DONE) {
1,189✔
251
      return false;
252
   }
253
   throw SQL_DB_Error(fmt("sqlite3_step failed - {}", ::sqlite3_errmsg(::sqlite3_db_handle(m_stmt))), rc);
×
254
}
255

256
Sqlite3_Database::Sqlite3_Statement::~Sqlite3_Statement() {
1,287✔
257
   ::sqlite3_finalize(m_stmt);
1,287✔
258
}
1,287✔
259

260
}  // namespace Botan
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc