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

randombit / botan / 6718203569

01 Nov 2023 09:54AM UTC coverage: 91.705% (+0.002%) from 91.703%
6718203569

push

github

web-flow
Merge pull request #3788 from randombit/sqlite3_update_todo

sqlite3 engine update proposal.

80143 of 87392 relevant lines covered (91.71%)

8599820.93 hits per line

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

82.83
/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 <sqlite3.h>
14

15
namespace Botan {
16

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

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

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

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

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

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

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

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

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

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

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

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

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

93
   if(rc != SQLITE_OK) {
820✔
94
      throw SQL_DB_Error(fmt("sqlite3_prepare failed on '{}' with err {}", base_sql, rc), rc);
44✔
95
   }
96
}
798✔
97

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

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

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

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

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

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

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

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

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

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

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

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

152
   return std::string(cast_uint8_ptr_to_char(str));
123✔
153
}
154

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

158
   const int sessions_int = ::sqlite3_column_int(m_stmt, column);
6✔
159

160
   BOTAN_ASSERT(sessions_int >= 0, "Expected size_t is non-negative");
6✔
161

162
   return static_cast<size_t>(sessions_int);
6✔
163
}
164

165
size_t Sqlite3_Database::Sqlite3_Statement::spin() {
583✔
166
   size_t steps = 0;
583✔
167
   while(step()) {
583✔
168
      ++steps;
×
169
   }
170

171
   return steps;
583✔
172
}
173

174
bool Sqlite3_Database::Sqlite3_Statement::step() {
949✔
175
   return (::sqlite3_step(m_stmt) == SQLITE_ROW);
949✔
176
}
177

178
Sqlite3_Database::Sqlite3_Statement::~Sqlite3_Statement() {
798✔
179
   ::sqlite3_finalize(m_stmt);
798✔
180
}
798✔
181

182
}  // 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