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

randombit / botan / 5356326050

23 Jun 2023 01:05PM UTC coverage: 91.728% (-0.008%) from 91.736%
5356326050

Pull #3595

github

web-flow
Merge a5b917599 into 92171c524
Pull Request #3595: Improve clang-tidy coverage

78163 of 85212 relevant lines covered (91.73%)

12690161.35 hits per line

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

82.18
/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) {
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 {
821✔
40
   return std::make_shared<Sqlite3_Statement>(m_db, base_sql);
821✔
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
   // TODO: Use sqlite3_changes64() introduced in SQLite 3.37
68
   //       (released 27th Nov 2021)
69
   const auto result = ::sqlite3_changes(m_db);
22✔
70
   BOTAN_ASSERT_NOMSG(result >= 0);
22✔
71
   return static_cast<size_t>(result);
22✔
72
}
73

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

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

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

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

95
   if(rc != SQLITE_OK) {
821✔
96
      throw SQL_DB_Error(fmt("sqlite3_prepare failed on '{}' with err {}", base_sql, rc), rc);
44✔
97
   }
98
}
799✔
99

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

107
void Sqlite3_Database::Sqlite3_Statement::bind(int column, size_t val) {
924✔
108
   // XXX: is this cast doing what we want?
109
   if(val != static_cast<size_t>(static_cast<int>(val))) {
924✔
110
      throw SQL_DB_Error("sqlite3 cannot store " + std::to_string(val) + " without truncation");
×
111
   }
112
   int rc = ::sqlite3_bind_int(m_stmt, column, static_cast<int>(val));
924✔
113
   if(rc != SQLITE_OK) {
924✔
114
      throw SQL_DB_Error("sqlite3_bind_int failed", rc);
×
115
   }
116
}
924✔
117

118
void Sqlite3_Database::Sqlite3_Statement::bind(int column, std::chrono::system_clock::time_point time) {
227✔
119
   const uint64_t timeval = std::chrono::duration_cast<std::chrono::seconds>(time.time_since_epoch()).count();
227✔
120
   bind(column, static_cast<size_t>(timeval));
227✔
121
}
227✔
122

123
void Sqlite3_Database::Sqlite3_Statement::bind(int column, const std::vector<uint8_t>& val) {
650✔
124
   int rc = ::sqlite3_bind_blob(m_stmt, column, val.data(), static_cast<int>(val.size()), SQLITE_TRANSIENT);
650✔
125
   if(rc != SQLITE_OK) {
650✔
126
      throw SQL_DB_Error("sqlite3_bind_text failed", rc);
×
127
   }
128
}
650✔
129

130
void Sqlite3_Database::Sqlite3_Statement::bind(int column, const uint8_t* p, size_t len) {
6✔
131
   int rc = ::sqlite3_bind_blob(m_stmt, column, p, static_cast<int>(len), SQLITE_TRANSIENT);
6✔
132
   if(rc != SQLITE_OK) {
6✔
133
      throw SQL_DB_Error("sqlite3_bind_text failed", rc);
×
134
   }
135
}
6✔
136

137
std::pair<const uint8_t*, size_t> Sqlite3_Database::Sqlite3_Statement::get_blob(int column) {
278✔
138
   const auto column_type = ::sqlite3_column_type(m_stmt, column);
278✔
139
   if(column_type == SQLITE_NULL) {
278✔
140
      return {nullptr, 0};
91✔
141
   }
142

143
   BOTAN_ASSERT(column_type == SQLITE_BLOB, "Return value is a blob");
187✔
144

145
   const void* session_blob = ::sqlite3_column_blob(m_stmt, column);
187✔
146
   const int session_blob_size = ::sqlite3_column_bytes(m_stmt, column);
187✔
147

148
   BOTAN_ASSERT(session_blob_size >= 0, "Blob size is non-negative");
187✔
149

150
   return std::make_pair(static_cast<const uint8_t*>(session_blob), static_cast<size_t>(session_blob_size));
187✔
151
}
152

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

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

158
   return std::string(cast_uint8_ptr_to_char(str));
123✔
159
}
160

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

164
   const int sessions_int = ::sqlite3_column_int(m_stmt, column);
6✔
165

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

168
   return static_cast<size_t>(sessions_int);
6✔
169
}
170

171
size_t Sqlite3_Database::Sqlite3_Statement::spin() {
585✔
172
   size_t steps = 0;
585✔
173
   while(step()) {
585✔
174
      ++steps;
×
175
   }
176

177
   return steps;
585✔
178
}
179

180
bool Sqlite3_Database::Sqlite3_Statement::step() {
950✔
181
   return (::sqlite3_step(m_stmt) == SQLITE_ROW);
950✔
182
}
183

184
Sqlite3_Database::Sqlite3_Statement::~Sqlite3_Statement() {
799✔
185
   ::sqlite3_finalize(m_stmt);
799✔
186
}
799✔
187

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

© 2025 Coveralls, Inc