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

randombit / botan / 16829546852

08 Aug 2025 11:42AM UTC coverage: 90.694% (+0.02%) from 90.677%
16829546852

Pull #5047

github

web-flow
Merge 38ab400ab into eaad5c540
Pull Request #5047: X.509 Path: Option for Non-Self-Signed Trust Anchors

100210 of 110492 relevant lines covered (90.69%)

12241134.4 hits per line

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

82.47
/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/exceptn.h>
11
#include <botan/mem_ops.h>
12
#include <botan/internal/fmt.h>
13
#include <botan/internal/int_utils.h>
14
#include <sqlite3.h>
15

16
namespace Botan {
17

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

25
   if(rc != 0) [[unlikely]] {
34✔
26
      const std::string err_msg = ::sqlite3_errmsg(m_db);
×
27
      ::sqlite3_close(m_db);
×
28
      m_db = nullptr;
×
29
      throw SQL_DB_Error("sqlite3_open failed - " + err_msg);
×
30
   }
×
31
}
34✔
32

33
Sqlite3_Database::~Sqlite3_Database() {
34✔
34
   if(m_db != nullptr) [[likely]] {
34✔
35
      ::sqlite3_close(m_db);
34✔
36
   }
37
   m_db = nullptr;
34✔
38
}
34✔
39

40
std::shared_ptr<SQL_Database::Statement> Sqlite3_Database::new_statement(std::string_view base_sql) const {
841✔
41
   return std::make_shared<Sqlite3_Statement>(m_db, base_sql);
841✔
42
}
43

44
size_t Sqlite3_Database::row_count(std::string_view table_name) {
22✔
45
   auto stmt = new_statement(fmt("select count(*) from {}", table_name));
43✔
46

47
   if(stmt->step()) {
1✔
48
      return stmt->get_size_t(0);
1✔
49
   } else {
50
      throw SQL_DB_Error(fmt("Querying size of table '{}' failed", table_name));
×
51
   }
52
}
1✔
53

54
void Sqlite3_Database::create_table(std::string_view table_schema) {
87✔
55
   char* errmsg = nullptr;
87✔
56
   int rc = ::sqlite3_exec(m_db, std::string(table_schema).c_str(), nullptr, nullptr, &errmsg);
87✔
57

58
   if(rc != SQLITE_OK) {
87✔
59
      const std::string err_msg = errmsg;
×
60
      ::sqlite3_free(errmsg);
×
61
      ::sqlite3_close(m_db);
×
62
      m_db = nullptr;
×
63
      throw SQL_DB_Error("sqlite3_exec for table failed - " + err_msg);
×
64
   }
×
65
}
87✔
66

67
size_t Sqlite3_Database::rows_changed_by_last_statement() {
22✔
68
   const auto result = ::sqlite3_changes64(m_db);
22✔
69
   BOTAN_ASSERT_NOMSG(result >= 0);
22✔
70
   return static_cast<size_t>(result);
22✔
71
}
72

73
bool Sqlite3_Database::is_threadsafe() const {
374✔
74
   const int flag = sqlite3_threadsafe();
374✔
75

76
   // `flag` can have three values:
77
   //
78
   // 0 - single threaded:  no locking is done inside the SQLite code
79
   // 1 - serialized:       all SQLite database features can be used safely
80
   //                       from multiple threads
81
   // 2 - reduced locking:  application must ensure not to use a single
82
   //                       database connection across threads
83
   //
84
   // https://www.sqlite.org/c3ref/threadsafe.html
85

86
   // When opening the database connection we explicitly request
87
   // SQLITE_OPEN_FULLMUTEX to ensure restrictive locking in SQLite.
88
   return flag >= 1;
374✔
89
}
90

91
Sqlite3_Database::Sqlite3_Statement::Sqlite3_Statement(sqlite3* db, std::string_view base_sql) : m_stmt{} {
841✔
92
   int rc = ::sqlite3_prepare_v2(db, base_sql.data(), static_cast<int>(base_sql.size()), &m_stmt, nullptr);
841✔
93

94
   if(rc != SQLITE_OK) {
841✔
95
      throw SQL_DB_Error(fmt("sqlite3_prepare failed on '{}' with err {}", base_sql, rc), rc);
22✔
96
   }
97
}
819✔
98

99
void Sqlite3_Database::Sqlite3_Statement::bind(int column, std::string_view val) {
752✔
100
   int rc = ::sqlite3_bind_text64(m_stmt, column, val.data(), val.size(), SQLITE_TRANSIENT, SQLITE_UTF8);
752✔
101
   if(rc != SQLITE_OK) {
752✔
102
      throw SQL_DB_Error("sqlite3_bind_text failed", rc);
×
103
   }
104
}
752✔
105

106
void Sqlite3_Database::Sqlite3_Statement::bind(int column, size_t val) {
956✔
107
   int rc = ::sqlite3_bind_int64(m_stmt, column, val);
956✔
108
   if(rc != SQLITE_OK) {
956✔
109
      throw SQL_DB_Error("sqlite3_bind_int failed", rc);
×
110
   }
111
}
956✔
112

113
void Sqlite3_Database::Sqlite3_Statement::bind(int column, std::chrono::system_clock::time_point time) {
235✔
114
   const uint64_t timeval = std::chrono::duration_cast<std::chrono::seconds>(time.time_since_epoch()).count();
235✔
115
   bind(column, static_cast<size_t>(timeval));
235✔
116
}
235✔
117

118
void Sqlite3_Database::Sqlite3_Statement::bind(int column, const std::vector<uint8_t>& val) {
666✔
119
   int rc = ::sqlite3_bind_blob64(m_stmt, column, val.data(), val.size(), SQLITE_TRANSIENT);
666✔
120
   if(rc != SQLITE_OK) {
666✔
121
      throw SQL_DB_Error("sqlite3_bind_text failed", rc);
×
122
   }
123
}
666✔
124

125
void Sqlite3_Database::Sqlite3_Statement::bind(int column, const uint8_t* p, size_t len) {
6✔
126
   int rc = ::sqlite3_bind_blob64(m_stmt, column, p, len, SQLITE_TRANSIENT);
6✔
127
   if(rc != SQLITE_OK) {
6✔
128
      throw SQL_DB_Error("sqlite3_bind_text failed", rc);
×
129
   }
130
}
6✔
131

132
std::pair<const uint8_t*, size_t> Sqlite3_Database::Sqlite3_Statement::get_blob(int column) {
286✔
133
   const auto column_type = ::sqlite3_column_type(m_stmt, column);
286✔
134
   if(column_type == SQLITE_NULL) {
286✔
135
      return {nullptr, 0};
95✔
136
   }
137

138
   BOTAN_ASSERT(column_type == SQLITE_BLOB, "Return value is a blob");
191✔
139

140
   const void* session_blob = ::sqlite3_column_blob(m_stmt, column);
191✔
141
   const int session_blob_size = ::sqlite3_column_bytes(m_stmt, column);
191✔
142

143
   BOTAN_ASSERT(session_blob_size >= 0, "Blob size is non-negative");
191✔
144

145
   return std::make_pair(static_cast<const uint8_t*>(session_blob), static_cast<size_t>(session_blob_size));
191✔
146
}
147

148
std::string Sqlite3_Database::Sqlite3_Statement::get_str(int column) {
127✔
149
   BOTAN_ASSERT(::sqlite3_column_type(m_stmt, column) == SQLITE_TEXT, "Return value is text");
127✔
150

151
   const unsigned char* str = ::sqlite3_column_text(m_stmt, column);
127✔
152

153
   return std::string(cast_uint8_ptr_to_char(str));
127✔
154
}
155

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

159
   return checked_cast_to<size_t>(::sqlite3_column_int64(m_stmt, column));
6✔
160
}
161

162
size_t Sqlite3_Database::Sqlite3_Statement::spin() {
601✔
163
   size_t steps = 0;
601✔
164
   while(step()) {
601✔
165
      ++steps;
×
166
   }
167

168
   return steps;
601✔
169
}
170

171
bool Sqlite3_Database::Sqlite3_Statement::step() {
974✔
172
   return (::sqlite3_step(m_stmt) == SQLITE_ROW);
974✔
173
}
174

175
Sqlite3_Database::Sqlite3_Statement::~Sqlite3_Statement() {
819✔
176
   ::sqlite3_finalize(m_stmt);
819✔
177
}
819✔
178

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

© 2026 Coveralls, Inc