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

randombit / botan / 5079590438

25 May 2023 12:28PM UTC coverage: 92.228% (+0.5%) from 91.723%
5079590438

Pull #3502

github

Pull Request #3502: Apply clang-format to the codebase

75589 of 81959 relevant lines covered (92.23%)

12139530.51 hits per line

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

81.63
/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
   m_db = nullptr;
34✔
36
}
34✔
37

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

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

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

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

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

64
size_t Sqlite3_Database::rows_changed_by_last_statement() {
22✔
65
   // TODO: Use sqlite3_changes64() introduced in SQLite 3.37
66
   //       (released 27th Nov 2021)
67
   const auto result = ::sqlite3_changes(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 {
360✔
73
   const int flag = sqlite3_threadsafe();
360✔
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;
360✔
88
}
89

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

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

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

103
void Sqlite3_Database::Sqlite3_Statement::bind(int column, size_t val) {
909✔
104
   if(val != static_cast<size_t>(static_cast<int>(val)))  // is this cast legit?
909✔
105
      throw SQL_DB_Error("sqlite3 cannot store " + std::to_string(val) + " without truncation");
×
106
   int rc = ::sqlite3_bind_int(m_stmt, column, static_cast<int>(val));
909✔
107
   if(rc != SQLITE_OK)
909✔
108
      throw SQL_DB_Error("sqlite3_bind_int failed", rc);
×
109
}
909✔
110

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

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

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

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

134
   BOTAN_ASSERT(column_type == SQLITE_BLOB, "Return value is a blob");
192✔
135

136
   const void* session_blob = ::sqlite3_column_blob(m_stmt, column);
192✔
137
   const int session_blob_size = ::sqlite3_column_bytes(m_stmt, column);
192✔
138

139
   BOTAN_ASSERT(session_blob_size >= 0, "Blob size is non-negative");
192✔
140

141
   return std::make_pair(static_cast<const uint8_t*>(session_blob), static_cast<size_t>(session_blob_size));
192✔
142
}
143

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

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

149
   return std::string(cast_uint8_ptr_to_char(str));
123✔
150
}
151

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

155
   const int sessions_int = ::sqlite3_column_int(m_stmt, column);
6✔
156

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

159
   return static_cast<size_t>(sessions_int);
6✔
160
}
161

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

168
   return steps;
575✔
169
}
170

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

173
Sqlite3_Database::Sqlite3_Statement::~Sqlite3_Statement() { ::sqlite3_finalize(m_stmt); }
792✔
174

175
}
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