GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/** |
||
2 |
* This file is part of the CernVM File System. |
||
3 |
*/ |
||
4 |
|||
5 |
#include "history_sql.h" |
||
6 |
|||
7 |
#include <cassert> |
||
8 |
|||
9 |
#include "util/string.h" |
||
10 |
|||
11 |
namespace history { |
||
12 |
|||
13 |
const float HistoryDatabase::kLatestSchema = 1.0; |
||
14 |
const float HistoryDatabase::kLatestSupportedSchema = 1.0; |
||
15 |
const unsigned HistoryDatabase::kLatestSchemaRevision = 3; |
||
16 |
|||
17 |
/** |
||
18 |
* Database Schema ChangeLog: |
||
19 |
* |
||
20 |
* Schema Version 1.0 |
||
21 |
* -> Revision 3: deprecate (flush) table 'recycle_bin' |
||
22 |
* add table 'branches' |
||
23 |
* add column 'branch' to table tags |
||
24 |
* -> Revision 2: add table 'recycle_bin' |
||
25 |
* -> Revision 1: add field 'size' |
||
26 |
* |
||
27 |
*/ |
||
28 |
|||
29 |
15 |
const std::string HistoryDatabase::kFqrnKey = "fqrn"; |
|
30 |
|||
31 |
|||
32 |
/** |
||
33 |
* This method creates a new database file and initializes the database schema. |
||
34 |
*/ |
||
35 |
83 |
bool HistoryDatabase::CreateEmptyDatabase() { |
|
36 |
✗✓ | 83 |
assert(read_write()); |
37 |
|||
38 |
83 |
sqlite::Sql sql_foreign_keys(sqlite_db(), "PRAGMA foreign_keys = ON;"); |
|
39 |
✗✓ | 83 |
if (!sql_foreign_keys.Execute()) |
40 |
return false; |
||
41 |
|||
42 |
return CreateBranchesTable() && |
||
43 |
CreateTagsTable() && |
||
44 |
✓✗✓✗ ✓✗ |
83 |
CreateRecycleBinTable(); |
45 |
} |
||
46 |
|||
47 |
|||
48 |
83 |
bool HistoryDatabase::CreateTagsTable() { |
|
49 |
✗✓ | 83 |
assert(read_write()); |
50 |
return sqlite::Sql(sqlite_db(), |
||
51 |
"CREATE TABLE tags (name TEXT, hash TEXT, revision INTEGER, " |
||
52 |
" timestamp INTEGER, channel INTEGER, description TEXT, size INTEGER, " |
||
53 |
" branch TEXT, CONSTRAINT pk_tags PRIMARY KEY (name), " |
||
54 |
83 |
" FOREIGN KEY (branch) REFERENCES branches (branch));").Execute(); |
|
55 |
} |
||
56 |
|||
57 |
|||
58 |
85 |
bool HistoryDatabase::CreateRecycleBinTable() { |
|
59 |
✗✓ | 85 |
assert(read_write()); |
60 |
return sqlite::Sql(sqlite_db(), |
||
61 |
"CREATE TABLE recycle_bin (hash TEXT, flags INTEGER, " |
||
62 |
85 |
" CONSTRAINT pk_hash PRIMARY KEY (hash))").Execute(); |
|
63 |
} |
||
64 |
|||
65 |
|||
66 |
86 |
bool HistoryDatabase::CreateBranchesTable() { |
|
67 |
✗✓ | 86 |
assert(read_write()); |
68 |
|||
69 |
sqlite::Sql sql_create(sqlite_db(), |
||
70 |
"CREATE TABLE branches (branch TEXT, parent TEXT, initial_revision INTEGER," |
||
71 |
" CONSTRAINT pk_branch PRIMARY KEY (branch), " |
||
72 |
" FOREIGN KEY (parent) REFERENCES branches (branch), " |
||
73 |
" CHECK ((branch <> '') OR (parent IS NULL)), " |
||
74 |
86 |
" CHECK ((branch = '') OR (parent IS NOT NULL)));"); |
|
75 |
86 |
bool retval = sql_create.Execute(); |
|
76 |
✗✓ | 86 |
if (!retval) |
77 |
return false; |
||
78 |
|||
79 |
sqlite::Sql sql_init(sqlite_db(), |
||
80 |
"INSERT INTO branches (branch, parent, initial_revision) " |
||
81 |
86 |
"VALUES ('', NULL, 0);"); |
|
82 |
86 |
retval = sql_init.Execute(); |
|
83 |
86 |
return retval; |
|
84 |
} |
||
85 |
|||
86 |
|||
87 |
83 |
bool HistoryDatabase::InsertInitialValues(const std::string &repository_name) { |
|
88 |
✗✓ | 83 |
assert(read_write()); |
89 |
83 |
return this->SetProperty(kFqrnKey, repository_name); |
|
90 |
} |
||
91 |
|||
92 |
|||
93 |
130 |
bool HistoryDatabase::ContainsRecycleBin() const { |
|
94 |
✓✗✓✓ |
130 |
return schema_version() >= 1.0 - kSchemaEpsilon && schema_revision() >= 2; |
95 |
} |
||
96 |
|||
97 |
|||
98 |
34 |
bool HistoryDatabase::CheckSchemaCompatibility() { |
|
99 |
return !((schema_version() < kLatestSupportedSchema - kSchemaEpsilon) || |
||
100 |
✓✗✓✗ |
34 |
(schema_version() > kLatestSchema + kSchemaEpsilon)); |
101 |
} |
||
102 |
|||
103 |
|||
104 |
8 |
bool HistoryDatabase::LiveSchemaUpgradeIfNecessary() { |
|
105 |
✗✓ | 8 |
assert(read_write()); |
106 |
✗✓ | 8 |
assert(IsEqualSchema(schema_version(), 1.0)); |
107 |
|||
108 |
8 |
sqlite::Sql sql_foreign_keys(sqlite_db(), "PRAGMA foreign_keys = ON;"); |
|
109 |
✗✓ | 8 |
if (!sql_foreign_keys.Execute()) |
110 |
return false; |
||
111 |
✓✓ | 8 |
if (schema_revision() == kLatestSchemaRevision) { |
112 |
5 |
return true; |
|
113 |
} |
||
114 |
|||
115 |
LogCvmfs(kLogHistory, kLogDebug, "upgrading history schema revision " |
||
116 |
"%.2f (Rev: %d) to %.2f (Rev: %d)", |
||
117 |
schema_version(), schema_revision(), |
||
118 |
3 |
kLatestSchema, kLatestSchemaRevision); |
|
119 |
|||
120 |
const bool success = UpgradeSchemaRevision_10_1() && |
||
121 |
UpgradeSchemaRevision_10_2() && |
||
122 |
✓✗✓✗ ✓✗ |
3 |
UpgradeSchemaRevision_10_3(); |
123 |
|||
124 |
✓✗✓✗ |
3 |
return success && StoreSchemaRevision(); |
125 |
} |
||
126 |
|||
127 |
|||
128 |
3 |
bool HistoryDatabase::UpgradeSchemaRevision_10_1() { |
|
129 |
✓✓ | 3 |
if (schema_revision() > 0) { |
130 |
2 |
return true; |
|
131 |
} |
||
132 |
|||
133 |
1 |
sqlite::Sql sql_upgrade(sqlite_db(), "ALTER TABLE tags ADD size INTEGER;"); |
|
134 |
✗✓ | 1 |
if (!sql_upgrade.Execute()) { |
135 |
LogCvmfs(kLogHistory, kLogStderr, "failed to upgrade tags table"); |
||
136 |
return false; |
||
137 |
} |
||
138 |
|||
139 |
1 |
set_schema_revision(1); |
|
140 |
1 |
return true; |
|
141 |
} |
||
142 |
|||
143 |
|||
144 |
3 |
bool HistoryDatabase::UpgradeSchemaRevision_10_2() { |
|
145 |
✓✓ | 3 |
if (schema_revision() > 1) { |
146 |
1 |
return true; |
|
147 |
} |
||
148 |
|||
149 |
✗✓ | 2 |
if (!CreateRecycleBinTable()) { |
150 |
LogCvmfs(kLogHistory, kLogStderr, "failed to upgrade history database"); |
||
151 |
return false; |
||
152 |
} |
||
153 |
|||
154 |
2 |
set_schema_revision(2); |
|
155 |
2 |
return true; |
|
156 |
} |
||
157 |
|||
158 |
|||
159 |
3 |
bool HistoryDatabase::UpgradeSchemaRevision_10_3() { |
|
160 |
✗✓ | 3 |
if (schema_revision() > 2) { |
161 |
return true; |
||
162 |
} |
||
163 |
|||
164 |
✗✓ | 3 |
if (!CreateBranchesTable()) { |
165 |
LogCvmfs(kLogHistory, kLogStderr, "failed to create branches table"); |
||
166 |
return false; |
||
167 |
} |
||
168 |
|||
169 |
sqlite::Sql sql_upgrade(sqlite_db(), |
||
170 |
3 |
"ALTER TABLE tags ADD branch TEXT REFERENCES branches (branch);"); |
|
171 |
✗✓ | 3 |
if (!sql_upgrade.Execute()) { |
172 |
LogCvmfs(kLogHistory, kLogStderr, "failed to upgrade tags table"); |
||
173 |
return false; |
||
174 |
} |
||
175 |
|||
176 |
3 |
sqlite::Sql sql_fill(sqlite_db(), "UPDATE tags SET branch = '';"); |
|
177 |
✗✓ | 3 |
if (!sql_fill.Execute()) { |
178 |
LogCvmfs(kLogHistory, kLogStderr, "failed to set branch default value"); |
||
179 |
return false; |
||
180 |
} |
||
181 |
|||
182 |
// We keep the table in the schema for backwards compatibility |
||
183 |
3 |
sqlite::Sql sql_flush(sqlite_db(), "DELETE FROM recycle_bin; VACUUM;"); |
|
184 |
✗✓ | 3 |
if (!sql_flush.Execute()) { |
185 |
LogCvmfs(kLogHistory, kLogStderr, "failed to flush recycle bin table"); |
||
186 |
return false; |
||
187 |
} |
||
188 |
|||
189 |
3 |
set_schema_revision(3); |
|
190 |
3 |
return true; |
|
191 |
} |
||
192 |
|||
193 |
|||
194 |
//------------------------------------------------------------------------------ |
||
195 |
|||
196 |
#define DB_FIELDS_V1R0 "name, hash, revision, timestamp, channel, " \ |
||
197 |
"description, 0, ''" |
||
198 |
#define DB_FIELDS_V1R1 "name, hash, revision, timestamp, channel, " \ |
||
199 |
"description, size, ''" |
||
200 |
#define DB_FIELDS_V1R3 "name, hash, revision, timestamp, channel, " \ |
||
201 |
"description, size, branch" |
||
202 |
#define DB_PLACEHOLDERS ":name, :hash, :revision, :timestamp, :channel, " \ |
||
203 |
":description, :size, :branch" |
||
204 |
#define ROLLBACK_COND "(revision > :target_rev OR " \ |
||
205 |
" name = :target_name) " \ |
||
206 |
"AND channel = :target_chan " \ |
||
207 |
"AND branch = ''" |
||
208 |
|||
209 |
#define MAKE_STATEMENT(STMT_TMPL, REV) \ |
||
210 |
static const std::string REV = \ |
||
211 |
ReplaceAll( \ |
||
212 |
ReplaceAll( \ |
||
213 |
ReplaceAll(STMT_TMPL, \ |
||
214 |
"@DB_FIELDS@", DB_FIELDS_ ## REV), \ |
||
215 |
"@DB_PLACEHOLDERS@", DB_PLACEHOLDERS), \ |
||
216 |
"@ROLLBACK_COND@", ROLLBACK_COND) |
||
217 |
|||
218 |
#define MAKE_STATEMENTS(STMT_TMPL) \ |
||
219 |
MAKE_STATEMENT(STMT_TMPL, V1R0); \ |
||
220 |
MAKE_STATEMENT(STMT_TMPL, V1R1); \ |
||
221 |
MAKE_STATEMENT(STMT_TMPL, V1R3) |
||
222 |
|||
223 |
#define DEFERRED_INIT(DB, REV) \ |
||
224 |
DeferredInit((DB)->sqlite_db(), (REV).c_str()) |
||
225 |
|||
226 |
#define DEFERRED_INITS(DB) \ |
||
227 |
if ((DB)->IsEqualSchema((DB)->schema_version(), 1.0f) && \ |
||
228 |
(DB)->schema_revision() == 0) { \ |
||
229 |
DEFERRED_INIT((DB), V1R0); \ |
||
230 |
} else if ((DB)->schema_revision() < 3) { \ |
||
231 |
DEFERRED_INIT((DB), V1R1); \ |
||
232 |
} else { \ |
||
233 |
DEFERRED_INIT((DB), V1R3); \ |
||
234 |
} |
||
235 |
|||
236 |
91 |
SqlInsertTag::SqlInsertTag(const HistoryDatabase *database) { |
|
237 |
✓✓✓✗ ✗✗✗✗ ✗✗✗✗ ✓✓✓✗ ✗✗✗✗ ✗✗✓✓ ✓✗ |
91 |
MAKE_STATEMENTS("INSERT INTO tags (@DB_FIELDS@) VALUES (@DB_PLACEHOLDERS@);"); |
238 |
✓✗✗✓ ✗✓✗✓ |
91 |
DEFERRED_INITS(database); |
239 |
} |
||
240 |
|||
241 |
|||
242 |
4268 |
bool SqlInsertTag::BindTag(const History::Tag &tag) { |
|
243 |
return |
||
244 |
BindText(1, tag.name) && |
||
245 |
BindTextTransient(2, tag.root_hash.ToString()) && // temporary (ToString) |
||
246 |
BindInt64(3, tag.revision) && |
||
247 |
BindInt64(4, tag.timestamp) && |
||
248 |
BindInt64(5, tag.channel) && |
||
249 |
BindText(6, tag.description) && |
||
250 |
BindInt64(7, tag.size) && |
||
251 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✗✗ |
4268 |
BindText(8, tag.branch); |
252 |
} |
||
253 |
|||
254 |
|||
255 |
//------------------------------------------------------------------------------ |
||
256 |
|||
257 |
|||
258 |
91 |
SqlRemoveTag::SqlRemoveTag(const HistoryDatabase *database) { |
|
259 |
91 |
DeferredInit(database->sqlite_db(), "DELETE FROM tags WHERE name = :name;"); |
|
260 |
} |
||
261 |
|||
262 |
12 |
bool SqlRemoveTag::BindName(const std::string &name) { |
|
263 |
12 |
return BindText(1, name); |
|
264 |
} |
||
265 |
|||
266 |
|||
267 |
//------------------------------------------------------------------------------ |
||
268 |
|||
269 |
|||
270 |
117 |
SqlFindTag::SqlFindTag(const HistoryDatabase *database) { |
|
271 |
✓✓✓✗ ✗✗✗✗ ✗✗✗✗ ✓✓✓✗ ✗✗✗✗ ✗✗✓✓ ✓✗ |
117 |
MAKE_STATEMENTS("SELECT @DB_FIELDS@ FROM tags WHERE name = :name;"); |
272 |
✓✗✓✓ ✓✓✓✓ |
117 |
DEFERRED_INITS(database); |
273 |
} |
||
274 |
|||
275 |
72 |
bool SqlFindTag::BindName(const std::string &name) { |
|
276 |
72 |
return BindText(1, name); |
|
277 |
} |
||
278 |
|||
279 |
|||
280 |
//------------------------------------------------------------------------------ |
||
281 |
|||
282 |
|||
283 |
117 |
SqlFindTagByDate::SqlFindTagByDate(const HistoryDatabase *database) { |
|
284 |
// figure out the tag that was HEAD to a given point in time |
||
285 |
// |
||
286 |
// conceptually goes back in the revision history | ORDER BY revision DESC |
||
287 |
// and picks the first tag | LIMIT 1 |
||
288 |
// that is older than the given timestamp | WHICH timestamp <= :ts |
||
289 |
MAKE_STATEMENTS("SELECT @DB_FIELDS@ FROM tags " |
||
290 |
"WHERE (branch = '') AND (timestamp <= :timestamp) " |
||
291 |
✓✓✓✗ ✗✗✗✗ ✗✗✗✗ ✓✓✓✗ ✗✗✗✗ ✗✗✓✓ ✓✗ |
117 |
"ORDER BY revision DESC LIMIT 1;"); |
292 |
✓✗✓✓ ✓✓✓✓ |
117 |
DEFERRED_INITS(database); |
293 |
} |
||
294 |
|||
295 |
8 |
bool SqlFindTagByDate::BindTimestamp(const time_t timestamp) { |
|
296 |
8 |
return BindInt64(1, timestamp); |
|
297 |
} |
||
298 |
|||
299 |
|||
300 |
//------------------------------------------------------------------------------ |
||
301 |
|||
302 |
|||
303 |
91 |
SqlFindBranchHead::SqlFindBranchHead(const HistoryDatabase *database) { |
|
304 |
// One of the tags with the highest revision on a given branch |
||
305 |
// Doesn't work on older database revisions |
||
306 |
MAKE_STATEMENTS("SELECT @DB_FIELDS@ FROM tags " |
||
307 |
"WHERE (branch = :branch) " |
||
308 |
✓✓✓✗ ✗✗✗✗ ✗✗✗✗ ✓✓✓✗ ✗✗✗✗ ✗✗✓✓ ✓✗ |
91 |
"ORDER BY revision DESC LIMIT 1;"); |
309 |
✓✗✗✓ ✗✓✗✓ |
91 |
DEFERRED_INITS(database); |
310 |
} |
||
311 |
|||
312 |
3 |
bool SqlFindBranchHead::BindBranchName(const std::string &branch_name) { |
|
313 |
3 |
return BindText(1, branch_name); |
|
314 |
} |
||
315 |
|||
316 |
|||
317 |
//------------------------------------------------------------------------------ |
||
318 |
|||
319 |
|||
320 |
117 |
SqlCountTags::SqlCountTags(const HistoryDatabase *database) { |
|
321 |
117 |
DeferredInit(database->sqlite_db(), "SELECT count(*) FROM tags;"); |
|
322 |
} |
||
323 |
|||
324 |
29 |
unsigned SqlCountTags::RetrieveCount() const { |
|
325 |
29 |
int64_t count = RetrieveInt64(0); |
|
326 |
✗✓ | 29 |
assert(count >= 0); |
327 |
29 |
return static_cast<uint64_t>(count); |
|
328 |
} |
||
329 |
|||
330 |
|||
331 |
//------------------------------------------------------------------------------ |
||
332 |
|||
333 |
|||
334 |
117 |
SqlListTags::SqlListTags(const HistoryDatabase *database) { |
|
335 |
MAKE_STATEMENTS( |
||
336 |
✓✓✓✗ ✗✗✗✗ ✗✗✗✗ ✓✓✓✗ ✗✗✗✗ ✗✗✓✓ ✓✗ |
117 |
"SELECT @DB_FIELDS@ FROM tags ORDER BY timestamp DESC, revision DESC;"); |
337 |
✓✗✓✓ ✓✓✓✓ |
117 |
DEFERRED_INITS(database); |
338 |
} |
||
339 |
|||
340 |
|||
341 |
//------------------------------------------------------------------------------ |
||
342 |
|||
343 |
|||
344 |
117 |
SqlGetChannelTips::SqlGetChannelTips(const HistoryDatabase *database) { |
|
345 |
MAKE_STATEMENTS("SELECT @DB_FIELDS@, MAX(revision) AS max_rev " |
||
346 |
"FROM tags " |
||
347 |
"WHERE branch = '' " |
||
348 |
✓✓✓✗ ✗✗✗✗ ✗✗✗✗ ✓✓✓✗ ✗✗✗✗ ✗✗✓✓ ✓✗ |
117 |
"GROUP BY channel;"); |
349 |
✓✗✓✓ ✓✓✓✓ |
117 |
DEFERRED_INITS(database); |
350 |
} |
||
351 |
|||
352 |
117 |
SqlGetHashes::SqlGetHashes(const HistoryDatabase *database) { |
|
353 |
DeferredInit(database->sqlite_db(), "SELECT DISTINCT hash FROM tags " |
||
354 |
117 |
"ORDER BY timestamp, revision ASC"); |
|
355 |
} |
||
356 |
|||
357 |
2001 |
shash::Any SqlGetHashes::RetrieveHash() const { |
|
358 |
return shash::MkFromHexPtr(shash::HexPtr(RetrieveString(0)), |
||
359 |
2001 |
shash::kSuffixCatalog); |
|
360 |
} |
||
361 |
|||
362 |
|||
363 |
//------------------------------------------------------------------------------ |
||
364 |
|||
365 |
|||
366 |
91 |
SqlRollbackTag::SqlRollbackTag(const HistoryDatabase *database) { |
|
367 |
✓✓✓✗ ✗✗✗✗ ✗✗✗✗ ✓✓✓✗ ✗✗✗✗ ✗✗✓✓ ✓✗ |
91 |
MAKE_STATEMENTS("DELETE FROM tags WHERE @ROLLBACK_COND@;"); |
368 |
✓✗✗✓ ✗✓✗✓ |
91 |
DEFERRED_INITS(database); |
369 |
} |
||
370 |
|||
371 |
|||
372 |
//------------------------------------------------------------------------------ |
||
373 |
|||
374 |
|||
375 |
117 |
SqlListRollbackTags::SqlListRollbackTags(const HistoryDatabase *database) { |
|
376 |
MAKE_STATEMENTS("SELECT @DB_FIELDS@ FROM tags " |
||
377 |
"WHERE @ROLLBACK_COND@ " |
||
378 |
✓✓✓✗ ✗✗✗✗ ✗✗✗✗ ✓✓✓✗ ✗✗✗✗ ✗✗✓✓ ✓✗ |
117 |
"ORDER BY revision DESC;"); |
379 |
✓✗✓✓ ✓✓✓✓ |
117 |
DEFERRED_INITS(database); |
380 |
} |
||
381 |
|||
382 |
|||
383 |
//------------------------------------------------------------------------------ |
||
384 |
|||
385 |
|||
386 |
117 |
SqlListBranches::SqlListBranches(const HistoryDatabase *database) { |
|
387 |
✓✓ | 117 |
if (database->schema_revision() < 3) |
388 |
3 |
DeferredInit(database->sqlite_db(), "SELECT '', NULL, 0;"); |
|
389 |
else |
||
390 |
DeferredInit(database->sqlite_db(), |
||
391 |
114 |
"SELECT branch, parent, initial_revision FROM branches;"); |
|
392 |
} |
||
393 |
|||
394 |
|||
395 |
27 |
History::Branch SqlListBranches::RetrieveBranch() const { |
|
396 |
27 |
std::string branch = RetrieveString(0); |
|
397 |
std::string parent = |
||
398 |
✓✓✗✗ ✓✓ |
27 |
(RetrieveType(1) == SQLITE_NULL) ? "" : RetrieveString(1); |
399 |
27 |
unsigned initial_revision = RetrieveInt64(2); |
|
400 |
27 |
return History::Branch(branch, parent, initial_revision); |
|
401 |
} |
||
402 |
|||
403 |
|||
404 |
//------------------------------------------------------------------------------ |
||
405 |
|||
406 |
|||
407 |
91 |
SqlInsertBranch::SqlInsertBranch(const HistoryDatabase *database) { |
|
408 |
DeferredInit(database->sqlite_db(), |
||
409 |
"INSERT INTO branches (branch, parent, initial_revision) " |
||
410 |
91 |
"VALUES (:branch, :parent, :initial_revision);"); |
|
411 |
} |
||
412 |
|||
413 |
|||
414 |
18 |
bool SqlInsertBranch::BindBranch(const History::Branch &branch) { |
|
415 |
return |
||
416 |
BindText(1, branch.branch) && |
||
417 |
BindText(2, branch.parent) && |
||
418 |
✓✓✓✗ ✓✗ |
18 |
BindInt64(3, branch.initial_revision); |
419 |
} |
||
420 |
|||
421 |
|||
422 |
//------------------------------------------------------------------------------ |
||
423 |
|||
424 |
|||
425 |
206 |
bool SqlRecycleBin::CheckSchema(const HistoryDatabase *database) const { |
|
426 |
return (database->IsEqualSchema(database->schema_version(), 1.0)) && |
||
427 |
✓✗✓✗ |
206 |
(database->schema_revision() >= 2); |
428 |
} |
||
429 |
|||
430 |
|||
431 |
//------------------------------------------------------------------------------ |
||
432 |
|||
433 |
|||
434 |
115 |
SqlRecycleBinList::SqlRecycleBinList(const HistoryDatabase *database) { |
|
435 |
✗✓ | 115 |
assert(CheckSchema(database)); |
436 |
115 |
DeferredInit(database->sqlite_db(), "SELECT hash, flags FROM recycle_bin;"); |
|
437 |
} |
||
438 |
|||
439 |
|||
440 |
1 |
shash::Any SqlRecycleBinList::RetrieveHash() { |
|
441 |
1 |
const unsigned int flags = RetrieveInt64(1); |
|
442 |
1 |
shash::Suffix suffix = shash::kSuffixNone; |
|
443 |
✓✗ | 1 |
if (flags & SqlRecycleBin::kFlagCatalog) { |
444 |
1 |
suffix = shash::kSuffixCatalog; |
|
445 |
} |
||
446 |
|||
447 |
1 |
return shash::MkFromHexPtr(shash::HexPtr(RetrieveString(0)), suffix); |
|
448 |
} |
||
449 |
|||
450 |
|||
451 |
//------------------------------------------------------------------------------ |
||
452 |
|||
453 |
|||
454 |
91 |
SqlRecycleBinFlush::SqlRecycleBinFlush(const HistoryDatabase *database) { |
|
455 |
✗✓ | 91 |
assert(CheckSchema(database)); |
456 |
91 |
DeferredInit(database->sqlite_db(), "DELETE FROM recycle_bin;"); |
|
457 |
} |
||
458 |
|||
459 |
|||
460 |
✓✗✓✗ |
45 |
}; /* namespace history */ |
Generated by: GCOVR (Version 4.1) |