GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/sql_impl.h
Date: 2026-10-25 02:40:14
Exec Total Coverage
Lines: 212 243 87.2%
Branches: 199 424 46.9%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM file system.
3 */
4
5 #ifndef CVMFS_SQL_IMPL_H_
6 #define CVMFS_SQL_IMPL_H_
7
8 #include <fcntl.h>
9
10 #include <cassert>
11 #include <cerrno>
12 #include <string>
13
14 #include "sql.h"
15 #include "sqlitemem.h"
16 #include "util/logging.h"
17 #include "util/platform.h"
18
19 namespace sqlite {
20
21 template<class DerivedT>
22 10687 Database<DerivedT>::Database(const std::string &filename,
23 const OpenMode open_mode)
24 10687 : database_(filename, this)
25 10687 , read_write_(kOpenReadWrite == open_mode)
26 10687 , schema_version_(0.0f)
27 10687 , schema_revision_(0) { }
28
29
30 template<class DerivedT>
31 5040 DerivedT *Database<DerivedT>::Create(const std::string &filename) {
32
2/4
✓ Branch 1 taken 5040 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5040 times.
✗ Branch 5 not taken.
5040 std::unique_ptr<DerivedT> database(new DerivedT(filename, kOpenReadWrite));
33
34
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5040 times.
5040 if (database.get() == nullptr) {
35 ✗ LogCvmfs(kLogSql, kLogDebug, "Failed to create new database object");
36 ✗ return NULL;
37 }
38
39 5040 database->set_schema_version(DerivedT::kLatestSchema);
40 5040 database->set_schema_revision(DerivedT::kLatestSchemaRevision);
41
42 5040 const int open_flags = SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READWRITE
43 | SQLITE_OPEN_CREATE;
44
2/4
✓ Branch 2 taken 5040 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5040 times.
5040 if (!database->OpenDatabase(open_flags)) {
45 ✗ LogCvmfs(kLogSql, kLogDebug, "Failed to create new database file");
46 ✗ return NULL;
47 }
48
49
2/4
✓ Branch 2 taken 5040 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5040 times.
5040 if (!database->CreatePropertiesTable()) {
50 ✗ database->PrintSqlError("Failed to create common properties table");
51 ✗ return NULL;
52 }
53
54
2/4
✓ Branch 2 taken 5040 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5040 times.
5040 if (!database->CreateEmptyDatabase()) {
55 ✗ database->PrintSqlError("Failed to create empty database");
56 ✗ return NULL;
57 }
58
59
2/4
✓ Branch 2 taken 5040 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5040 times.
5040 if (!database->PrepareCommonQueries()) {
60 ✗ database->PrintSqlError("Failed to initialize properties queries");
61 ✗ return NULL;
62 }
63
64
2/4
✓ Branch 2 taken 5040 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5040 times.
5040 if (!database->StoreSchemaRevision()) {
65 ✗ database->PrintSqlError("Failed to store initial schema revision");
66 ✗ return NULL;
67 }
68
69 5040 return database.release();
70 5040 }
71
72
73 template<class DerivedT>
74 5647 DerivedT *Database<DerivedT>::Open(const std::string &filename,
75 const OpenMode open_mode) {
76
2/4
✓ Branch 1 taken 5647 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5647 times.
✗ Branch 5 not taken.
5647 std::unique_ptr<DerivedT> database(new DerivedT(filename, open_mode));
77
78
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5647 times.
5647 if (database.get() == nullptr) {
79 ✗ LogCvmfs(kLogSql, kLogDebug,
80 "Failed to open database file '%s' - errno: %d", filename.c_str(),
81 ✗ errno);
82 ✗ return NULL;
83 }
84
85
3/4
✓ Branch 2 taken 5647 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 90 times.
✓ Branch 5 taken 5557 times.
5647 if (!database->Initialize()) {
86 90 return NULL;
87 }
88
89 5557 return database.release();
90 5647 }
91
92
93 template<class DerivedT>
94 5647 bool Database<DerivedT>::Initialize() {
95
2/2
✓ Branch 0 taken 3259 times.
✓ Branch 1 taken 2388 times.
5647 const int flags = (read_write_) ? SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READWRITE
96 : SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READONLY;
97
98
2/4
✓ Branch 2 taken 5575 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 5575 times.
✗ Branch 6 not taken.
11222 bool const successful = OpenDatabase(flags) && Configure() && FileReadAhead()
99
3/4
✓ Branch 0 taken 5575 times.
✓ Branch 1 taken 72 times.
✓ Branch 3 taken 5575 times.
✗ Branch 4 not taken.
11222 && PrepareCommonQueries();
100
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 5575 times.
5647 if (!successful) {
101 72 LogCvmfs(kLogSql, kLogDebug, "failed to open database file '%s'",
102 72 filename().c_str());
103 72 return false;
104 }
105
106 5575 ReadSchemaRevision();
107 5575 LogCvmfs(kLogSql, kLogDebug,
108 "opened database with schema version %f "
109 "and revision %u",
110 5575 schema_version_, schema_revision_);
111
112
2/2
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 5566 times.
5575 if (!static_cast<DerivedT *>(this)->CheckSchemaCompatibility()) {
113 18 LogCvmfs(kLogSql, kLogDebug, "schema version %f not supported (%s)",
114 9 schema_version_, filename().c_str());
115 9 return false;
116 }
117
118 11132 if (read_write_
119
6/6
✓ Branch 0 taken 3250 times.
✓ Branch 1 taken 2316 times.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 3241 times.
✓ Branch 5 taken 9 times.
✓ Branch 6 taken 5557 times.
5566 && !static_cast<DerivedT *>(this)->LiveSchemaUpgradeIfNecessary()) {
120 9 LogCvmfs(kLogSql, kLogDebug, "failed tp upgrade schema revision");
121 9 return false;
122 }
123
124 5557 return true;
125 }
126
127
128 template<class DerivedT>
129 10687 bool Database<DerivedT>::OpenDatabase(const int flags) {
130 // Open database file (depending on the flags read-only or read-write)
131 10687 LogCvmfs(kLogSql, kLogDebug, "opening database file %s", filename().c_str());
132 10687 int const retval = sqlite3_open_v2(filename().c_str(),
133 &database_.sqlite_db,
134 flags | SQLITE_OPEN_EXRESCODE,
135 NULL);
136
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 10615 times.
10687 if (retval != SQLITE_OK) {
137 72 LogCvmfs(kLogSql, kLogDebug, "cannot open database file %s (%d - %d)",
138 72 filename().c_str(), retval, errno);
139 72 return false;
140 }
141
142 10615 return true;
143 }
144
145
146 template<class DerivedT>
147 11521 Database<DerivedT>::DatabaseRaiiWrapper::~DatabaseRaiiWrapper() {
148
1/2
✓ Branch 0 taken 10684 times.
✗ Branch 1 not taken.
11521 if (NULL != sqlite_db) {
149 11521 const bool close_successful = Close();
150
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10684 times.
11521 assert(close_successful);
151 }
152 11521 }
153
154
155 template<class DerivedT>
156 11521 bool Database<DerivedT>::DatabaseRaiiWrapper::Close() {
157
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10684 times.
11521 assert(NULL != sqlite_db);
158
159
2/2
✓ Branch 0 taken 2698 times.
✓ Branch 1 taken 7986 times.
23042 LogCvmfs(kLogSql, kLogDebug, "closing SQLite database '%s' (unlink: %s)",
160 23042 filename().c_str(), (db_file_guard.IsEnabled() ? "yes" : "no"));
161 11521 const int result = sqlite3_close(sqlite_db);
162
163
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10684 times.
11521 if (result != SQLITE_OK) {
164 ✗ LogCvmfs(kLogSql, kLogDebug,
165 "failed to close SQLite database '%s' (%d - %s)",
166 ✗ filename().c_str(), result, delegate_->GetLastErrorMsg().c_str());
167 ✗ return false;
168 }
169
170 11521 sqlite_db = NULL;
171
2/2
✓ Branch 0 taken 1104 times.
✓ Branch 1 taken 9580 times.
11521 if (lookaside_buffer != NULL) {
172 1104 SqliteMemoryManager::GetInstance()->ReleaseLookasideBuffer(
173 lookaside_buffer);
174 1104 lookaside_buffer = NULL;
175 }
176 11521 return true;
177 }
178
179
180 template<class DerivedT>
181 5575 bool Database<DerivedT>::Configure() {
182 // Read-only databases should store temporary files in memory. This avoids
183 // unexpected open read-write file descriptors in the cache directory like
184 // etilqs_<number>. They also use the optimized memory manager, if it is
185 // available.
186
2/2
✓ Branch 0 taken 2316 times.
✓ Branch 1 taken 3259 times.
5575 if (!read_write_) {
187
2/2
✓ Branch 1 taken 1104 times.
✓ Branch 2 taken 1212 times.
2316 if (SqliteMemoryManager::HasInstance()) {
188 1104 database_.lookaside_buffer = SqliteMemoryManager::GetInstance()
189 1104 ->AssignLookasideBuffer(sqlite_db());
190 }
191
192
5/16
✓ Branch 1 taken 2316 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2316 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2316 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2316 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 2316 times.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
4632 return Sql(sqlite_db(), "PRAGMA temp_store=2;").Execute()
193
11/29
✓ Branch 2 taken 2316 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2316 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 2316 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 2316 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 2316 times.
✗ Branch 15 not taken.
✓ Branch 17 taken 2316 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 2316 times.
✗ Branch 20 not taken.
✓ Branch 21 taken 2316 times.
✗ Branch 22 not taken.
✓ Branch 24 taken 2316 times.
✗ Branch 25 not taken.
✓ Branch 27 taken 2316 times.
✗ Branch 28 not taken.
✓ Branch 30 taken 2316 times.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
4632 && Sql(sqlite_db(), "PRAGMA locking_mode=EXCLUSIVE;").Execute();
194 }
195 3259 return true;
196 }
197
198
199 template<class DerivedT>
200 5575 bool Database<DerivedT>::FileReadAhead() {
201 // Read-ahead into file system buffers
202 // TODO(jblomer): mmap, re-readahead
203
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 5575 times.
5575 assert(filename().length() > 1);
204 int fd_readahead;
205
2/2
✓ Branch 2 taken 4471 times.
✓ Branch 3 taken 1104 times.
5575 if (filename()[0] != '@') {
206 4471 fd_readahead = open(filename().c_str(), O_RDONLY);
207
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4471 times.
4471 if (fd_readahead < 0) {
208 ✗ LogCvmfs(kLogSql, kLogDebug, "failed to open %s for read-ahead (%d)",
209 ✗ filename().c_str(), errno);
210 ✗ return false;
211 }
212 4471 const ssize_t retval = platform_readahead(fd_readahead);
213 4471 close(fd_readahead);
214
215 // Read-ahead is known to fail on tmpfs with EINVAL
216 // EINVAL = "readahead() cannot be applied to that a file type"
217 // It can also fail with ENOSYS on kernel interfaces that do not implement
218 // readahead(), such as LX-Brand zones on illumos.
219 // Don't consider either a fatal error.
220
2/6
✓ Branch 0 taken 4471 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4471 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
4471 if (retval != 0 && errno != EINVAL && errno != ENOSYS) {
221 ✗ LogCvmfs(kLogSql, kLogDebug | kLogSyslogWarn,
222 "failed to read-ahead %s: invalid file descrp. or not open for "
223 "reading (%d)",
224 ✗ filename().c_str(), errno);
225 ✗ return false;
226 }
227 }
228
229 5575 return true;
230 }
231
232
233 template<class DerivedT>
234 10615 bool Database<DerivedT>::PrepareCommonQueries() {
235 10615 sqlite3 *db = sqlite_db();
236
3/6
✓ Branch 2 taken 10615 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 10615 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 10615 times.
✗ Branch 9 not taken.
10615 begin_transaction_ = std::unique_ptr<Sql>(new Sql(db, "BEGIN;"));
237
3/6
✓ Branch 2 taken 10615 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 10615 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 10615 times.
✗ Branch 9 not taken.
10615 commit_transaction_ = std::unique_ptr<Sql>(new Sql(db, "COMMIT;"));
238
1/2
✓ Branch 2 taken 10615 times.
✗ Branch 3 not taken.
21230 has_property_ = std::unique_ptr<Sql>(
239
2/4
✓ Branch 1 taken 10615 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10615 times.
✗ Branch 5 not taken.
10615 new Sql(db, "SELECT count(*) FROM properties "
240 "WHERE key = :key;"));
241
3/6
✓ Branch 2 taken 10615 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 10615 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 10615 times.
✗ Branch 9 not taken.
10615 get_property_ = std::unique_ptr<Sql>(new Sql(db,
242 "SELECT value FROM properties "
243 "WHERE key = :key;"));
244
1/2
✓ Branch 2 taken 10615 times.
✗ Branch 3 not taken.
21230 set_property_ = std::unique_ptr<Sql>(
245
2/4
✓ Branch 1 taken 10615 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10615 times.
✗ Branch 5 not taken.
10615 new Sql(db, "INSERT OR REPLACE INTO properties "
246 "(key, value) VALUES (:key, :value);"));
247 10615 return (begin_transaction_.get() != nullptr
248
1/2
✓ Branch 1 taken 10615 times.
✗ Branch 2 not taken.
10615 && commit_transaction_.get() != nullptr
249
2/4
✓ Branch 1 taken 10615 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10615 times.
✗ Branch 5 not taken.
10615 && has_property_.get() != nullptr && get_property_.get() != nullptr
250
2/4
✓ Branch 0 taken 10615 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 10615 times.
✗ Branch 4 not taken.
21230 && set_property_.get() != nullptr);
251 }
252
253
254 template<class DerivedT>
255 5575 void Database<DerivedT>::ReadSchemaRevision() {
256
2/4
✓ Branch 2 taken 5575 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 5575 times.
✗ Branch 6 not taken.
11150 schema_version_ = (this->HasProperty(kSchemaVersionKey))
257
5/15
✓ Branch 0 taken 5575 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 5575 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 5575 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 5575 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 5575 times.
✗ Branch 13 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
5575 ? this->GetProperty<double>(kSchemaVersionKey)
258 : 1.0;
259
2/4
✓ Branch 2 taken 5575 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 5575 times.
✗ Branch 6 not taken.
11150 schema_revision_ = (this->HasProperty(kSchemaRevisionKey))
260
8/15
✓ Branch 0 taken 5476 times.
✓ Branch 1 taken 99 times.
✓ Branch 4 taken 5476 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 5476 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 5476 times.
✓ Branch 10 taken 99 times.
✓ Branch 12 taken 5476 times.
✓ Branch 13 taken 99 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
5575 ? this->GetProperty<int>(kSchemaRevisionKey)
261 : 0;
262 5575 }
263
264
265 template<class DerivedT>
266 5394 bool Database<DerivedT>::StoreSchemaRevision() {
267
2/9
✓ Branch 1 taken 5394 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 5394 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
10788 return this->SetProperty(kSchemaVersionKey, schema_version_)
268
8/22
✓ Branch 2 taken 5394 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5394 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 5394 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 5394 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 5394 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 5394 times.
✗ Branch 16 not taken.
✓ Branch 18 taken 5394 times.
✗ Branch 19 not taken.
✓ Branch 21 taken 5394 times.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
16182 && this->SetProperty(kSchemaRevisionKey, schema_revision_);
269 }
270
271
272 template<class DerivedT>
273 5570 bool Database<DerivedT>::BeginTransaction() const {
274
3/4
✓ Branch 2 taken 5543 times.
✓ Branch 3 taken 27 times.
✓ Branch 6 taken 5543 times.
✗ Branch 7 not taken.
5570 return begin_transaction_->Execute() && begin_transaction_->Reset();
275 }
276
277
278 template<class DerivedT>
279 5418 bool Database<DerivedT>::CommitTransaction() const {
280
2/4
✓ Branch 2 taken 5418 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 5418 times.
✗ Branch 7 not taken.
5418 return commit_transaction_->Execute() && commit_transaction_->Reset();
281 }
282
283
284 template<class DerivedT>
285 5040 bool Database<DerivedT>::CreatePropertiesTable() {
286
3/6
✓ Branch 2 taken 5040 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 5040 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 5040 times.
✗ Branch 9 not taken.
10080 return Sql(sqlite_db(),
287 "CREATE TABLE properties (key TEXT, value TEXT, "
288 "CONSTRAINT pk_properties PRIMARY KEY (key));")
289
1/2
✓ Branch 1 taken 5040 times.
✗ Branch 2 not taken.
10080 .Execute();
290 }
291
292
293 template<class DerivedT>
294 31034 bool Database<DerivedT>::HasProperty(const std::string &key) const {
295
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 31034 times.
31034 assert(has_property_.get() != nullptr);
296 31034 const bool retval = has_property_->BindText(1, key)
297
2/4
✓ Branch 0 taken 31034 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 31034 times.
✗ Branch 5 not taken.
31034 && has_property_->FetchRow();
298
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31034 times.
31034 assert(retval);
299 31034 const bool result = has_property_->RetrieveInt64(0) > 0;
300 31034 has_property_->Reset();
301 31034 return result;
302 }
303
304 template<class DerivedT>
305 template<typename T>
306 41474 T Database<DerivedT>::GetProperty(const std::string &key) const {
307
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 20737 times.
41474 assert(get_property_.get() != nullptr);
308 41474 const bool retval = get_property_->BindText(1, key)
309
2/4
✓ Branch 0 taken 20737 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 20737 times.
✗ Branch 5 not taken.
41474 && get_property_->FetchRow();
310
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20737 times.
41474 assert(retval);
311 41474 const T result = get_property_->Retrieve<T>(0);
312
1/2
✓ Branch 2 taken 2701 times.
✗ Branch 3 not taken.
41474 get_property_->Reset();
313 41474 return result;
314 }
315
316 template<class DerivedT>
317 template<typename T>
318 20030 T Database<DerivedT>::GetPropertyDefault(const std::string &key,
319 const T default_value) const {
320
2/2
✓ Branch 1 taken 4603 times.
✓ Branch 2 taken 5412 times.
20030 return (HasProperty(key)) ? GetProperty<T>(key) : default_value;
321 }
322
323 template<class DerivedT>
324 template<typename T>
325 56484 bool Database<DerivedT>::SetProperty(const std::string &key, const T value) {
326
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 28544 times.
56484 assert(set_property_.get() != nullptr);
327
1/2
✓ Branch 4 taken 28544 times.
✗ Branch 5 not taken.
112968 return set_property_->BindText(1, key) && set_property_->Bind(2, value)
328
3/6
✓ Branch 0 taken 28544 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 28544 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 28544 times.
✗ Branch 9 not taken.
112968 && set_property_->Execute() && set_property_->Reset();
329 }
330
331 template<class DerivedT>
332 ✗ std::string Database<DerivedT>::GetLastErrorMsg() const {
333 ✗ std::string msg = sqlite3_errmsg(sqlite_db());
334 ✗ return msg;
335 }
336
337
338 template<class DerivedT>
339 2764 void Database<DerivedT>::TakeFileOwnership() {
340 2764 database_.TakeFileOwnership();
341 2764 LogCvmfs(kLogSql, kLogDebug, "Database object took ownership of '%s'",
342 2764 database_.filename().c_str());
343 2764 }
344
345
346 template<class DerivedT>
347 63 void Database<DerivedT>::DropFileOwnership() {
348 63 database_.DropFileOwnership();
349 63 LogCvmfs(kLogSql, kLogDebug, "Database object dropped ownership of '%s'",
350 63 database_.filename().c_str());
351 63 }
352
353
354 template<class DerivedT>
355 99 unsigned Database<DerivedT>::GetModifiedRowCount() const {
356 99 const int modified_rows = sqlite3_total_changes(sqlite_db());
357
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 99 times.
99 assert(modified_rows >= 0);
358 99 return static_cast<unsigned>(modified_rows);
359 }
360
361 /**
362 * Ask SQlite for per-connection memory statistics
363 */
364 template<class DerivedT>
365 34 void Database<DerivedT>::GetMemStatistics(MemStatistics *stats) const {
366 34 const int reset = 0;
367 int current;
368 int highwater;
369 34 int retval = SQLITE_OK;
370
2/4
✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 34 times.
✗ Branch 5 not taken.
34 retval |= sqlite3_db_status(sqlite_db(), SQLITE_DBSTATUS_LOOKASIDE_USED,
371 &current, &highwater, reset);
372 34 stats->lookaside_slots_used = current;
373 34 stats->lookaside_slots_max = highwater;
374
2/4
✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 34 times.
✗ Branch 5 not taken.
34 retval |= sqlite3_db_status(sqlite_db(), SQLITE_DBSTATUS_LOOKASIDE_HIT,
375 &current, &highwater, reset);
376 34 stats->lookaside_hit = highwater;
377
2/4
✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 34 times.
✗ Branch 5 not taken.
34 retval |= sqlite3_db_status(sqlite_db(), SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE,
378 &current, &highwater, reset);
379 34 stats->lookaside_miss_size = highwater;
380
2/4
✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 34 times.
✗ Branch 5 not taken.
34 retval |= sqlite3_db_status(sqlite_db(), SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL,
381 &current, &highwater, reset);
382 34 stats->lookaside_miss_full = highwater;
383
2/4
✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 34 times.
✗ Branch 5 not taken.
34 retval |= sqlite3_db_status(sqlite_db(), SQLITE_DBSTATUS_CACHE_USED, &current,
384 &highwater, reset);
385 34 stats->page_cache_used = current;
386
2/4
✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 34 times.
✗ Branch 5 not taken.
34 retval |= sqlite3_db_status(sqlite_db(), SQLITE_DBSTATUS_CACHE_HIT, &current,
387 &highwater, reset);
388 34 stats->page_cache_hit = current;
389
2/4
✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 34 times.
✗ Branch 5 not taken.
34 retval |= sqlite3_db_status(sqlite_db(), SQLITE_DBSTATUS_CACHE_MISS, &current,
390 &highwater, reset);
391 34 stats->page_cache_miss = current;
392
2/4
✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 34 times.
✗ Branch 5 not taken.
34 retval |= sqlite3_db_status(sqlite_db(), SQLITE_DBSTATUS_SCHEMA_USED,
393 &current, &highwater, reset);
394 34 stats->schema_used = current;
395
2/4
✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 34 times.
✗ Branch 5 not taken.
34 retval |= sqlite3_db_status(sqlite_db(), SQLITE_DBSTATUS_STMT_USED, &current,
396 &highwater, reset);
397 34 stats->stmt_used = current;
398
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 assert(retval == SQLITE_OK);
399 34 }
400
401
402 template<class DerivedT>
403 1466 double Database<DerivedT>::GetFreePageRatio() const {
404
3/6
✓ Branch 2 taken 1466 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1466 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1466 times.
✗ Branch 9 not taken.
2932 Sql free_page_count_query(this->sqlite_db(), "PRAGMA freelist_count;");
405
3/6
✓ Branch 2 taken 1466 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1466 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1466 times.
✗ Branch 9 not taken.
2932 Sql page_count_query(this->sqlite_db(), "PRAGMA page_count;");
406
407
1/2
✓ Branch 1 taken 1466 times.
✗ Branch 2 not taken.
1466 const bool retval = page_count_query.FetchRow()
408
3/6
✓ Branch 0 taken 1466 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 1466 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1466 times.
✗ Branch 6 not taken.
1466 && free_page_count_query.FetchRow();
409
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1466 times.
1466 assert(retval);
410
411
1/2
✓ Branch 1 taken 1466 times.
✗ Branch 2 not taken.
1466 const int64_t pages = page_count_query.RetrieveInt64(0);
412
1/2
✓ Branch 1 taken 1466 times.
✗ Branch 2 not taken.
1466 const int64_t free_pages = free_page_count_query.RetrieveInt64(0);
413
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1466 times.
1466 assert(pages > 0);
414
415 1466 return (static_cast<double>(free_pages) / static_cast<double>(pages));
416 1466 }
417
418
419 template<class DerivedT>
420 336 bool Database<DerivedT>::Vacuum() const {
421
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 336 times.
336 assert(read_write_);
422 618 return static_cast<const DerivedT *>(this)->CompactDatabase()
423
20/36
✓ Branch 1 taken 327 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 282 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 45 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 282 times.
✓ Branch 8 taken 45 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 282 times.
✓ Branch 11 taken 45 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 282 times.
✓ Branch 14 taken 45 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 327 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 327 times.
✓ Branch 19 taken 9 times.
✓ Branch 20 taken 282 times.
✓ Branch 21 taken 45 times.
✓ Branch 22 taken 9 times.
✓ Branch 23 taken 282 times.
✓ Branch 24 taken 45 times.
✓ Branch 25 taken 9 times.
✓ Branch 26 taken 282 times.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
336 && Sql(this->sqlite_db(), "VACUUM;").Execute();
424 }
425
426
427 template<class DerivedT>
428 ✗ void Database<DerivedT>::PrintSqlError(const std::string &error_msg) {
429 ✗ LogCvmfs(kLogSql, kLogStderr, "%s\nSQLite said: '%s'", error_msg.c_str(),
430 this->GetLastErrorMsg().c_str());
431 }
432
433 template<class DerivedT>
434 const float Database<DerivedT>::kSchemaEpsilon = 0.0005;
435 template<class DerivedT>
436 const char *Database<DerivedT>::kSchemaVersionKey = "schema";
437 template<class DerivedT>
438 const char *Database<DerivedT>::kSchemaRevisionKey = "schema_revision";
439
440
441 //
442 // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
443 //
444
445
446 template<>
447 2706 inline bool Sql::Bind(const int index, const int &value) {
448 2706 return this->BindInt64(index, value);
449 }
450
451 template<>
452 5734 inline bool Sql::Bind(const int index, const unsigned int &value) {
453 5734 return this->BindInt64(index, static_cast<int>(value));
454 }
455
456 template<>
457 9304 inline bool Sql::Bind(const int index, const uint64_t &value) {
458 9304 return this->BindInt64(index, static_cast<int64_t>(value));
459 }
460
461 template<>
462 inline bool Sql::Bind(const int index, const sqlite3_int64 &value) {
463 return this->BindInt64(index, value);
464 }
465
466 template<>
467 5370 inline bool Sql::Bind(const int index, const std::string &value) {
468 5370 return this->BindTextTransient(index, value);
469 }
470
471 template<>
472 5394 inline bool Sql::Bind(const int index, const float &value) {
473 5394 return this->BindDouble(index, value);
474 }
475
476 template<>
477 36 inline bool Sql::Bind(const int index, const double &value) {
478 36 return this->BindDouble(index, value);
479 }
480
481
482 template<>
483 7885 inline int Sql::Retrieve(const int index) {
484 7885 return static_cast<int>(this->RetrieveInt64(index));
485 }
486
487 template<>
488 ✗ inline bool Sql::Retrieve(const int index) {
489 ✗ return static_cast<bool>(this->RetrieveInt(index));
490 }
491
492 template<>
493 inline sqlite3_int64 Sql::Retrieve(const int index) {
494 return this->RetrieveInt64(index);
495 }
496
497 template<>
498 4513 inline uint64_t Sql::Retrieve(const int index) {
499 4513 return static_cast<uint64_t>(this->RetrieveInt64(index));
500 }
501
502 template<>
503 2971 inline std::string Sql::Retrieve(const int index) {
504 2971 return RetrieveString(index);
505 }
506
507 template<>
508 36 inline float Sql::Retrieve(const int index) {
509 36 return static_cast<float>(this->RetrieveDouble(index));
510 }
511
512 template<>
513 5611 inline double Sql::Retrieve(const int index) {
514 5611 return this->RetrieveDouble(index);
515 }
516
517 } // namespace sqlite
518
519 #endif // CVMFS_SQL_IMPL_H_
520