Directory: | src/ |
---|---|
File: | src/storage_sqlite.c |
Date: | 2024-04-25 03:45:42 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 245 | 338 | 72.5% |
Branches: | 66 | 156 | 42.3% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * Copyright (c) 2022 Egor Tensin <egor@tensin.name> | ||
3 | * This file is part of the "cimple" project. | ||
4 | * For details, see https://github.com/egor-tensin/cimple. | ||
5 | * Distributed under the MIT License. | ||
6 | */ | ||
7 | |||
8 | #include "storage_sqlite.h" | ||
9 | #include "log.h" | ||
10 | #include "process.h" | ||
11 | #include "run_queue.h" | ||
12 | #include "sql/sqlite_sql.h" | ||
13 | #include "sqlite.h" | ||
14 | #include "storage.h" | ||
15 | |||
16 | #include <sqlite3.h> | ||
17 | |||
18 | #include <pthread.h> | ||
19 | #include <stdio.h> | ||
20 | #include <stdlib.h> | ||
21 | #include <string.h> | ||
22 | |||
23 | struct storage_sqlite_settings { | ||
24 | char *path; | ||
25 | }; | ||
26 | |||
27 | 29 | int storage_sqlite_settings_create(struct storage_settings *settings, const char *path) | |
28 | { | ||
29 | 29 | struct storage_sqlite_settings *sqlite = malloc(sizeof(struct storage_sqlite_settings)); | |
30 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (!sqlite) { |
31 | ✗ | log_errno("malloc"); | |
32 | ✗ | return -1; | |
33 | } | ||
34 | |||
35 | 29 | sqlite->path = strdup(path); | |
36 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (!sqlite->path) { |
37 | ✗ | log_errno("strdup"); | |
38 | ✗ | goto free; | |
39 | } | ||
40 | |||
41 | 29 | settings->type = STORAGE_TYPE_SQLITE; | |
42 | 29 | settings->sqlite = sqlite; | |
43 | 29 | return 0; | |
44 | |||
45 | ✗ | free: | |
46 | ✗ | free(sqlite); | |
47 | |||
48 | ✗ | return -1; | |
49 | } | ||
50 | |||
51 | 29 | void storage_sqlite_settings_destroy(const struct storage_settings *settings) | |
52 | { | ||
53 | 29 | free(settings->sqlite->path); | |
54 | 29 | free(settings->sqlite); | |
55 | 29 | } | |
56 | |||
57 | struct prepared_stmt { | ||
58 | pthread_mutex_t mtx; | ||
59 | sqlite3_stmt *impl; | ||
60 | }; | ||
61 | |||
62 | 174 | static int prepared_stmt_init(struct prepared_stmt *stmt, sqlite3 *db, const char *sql) | |
63 | { | ||
64 | 174 | int ret = 0; | |
65 | |||
66 | 174 | ret = pthread_mutex_init(&stmt->mtx, NULL); | |
67 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 174 times.
|
174 | if (ret) { |
68 | ✗ | pthread_errno(ret, "pthread_mutex_init"); | |
69 | ✗ | return ret; | |
70 | } | ||
71 | |||
72 | 174 | ret = sqlite_prepare(db, sql, &stmt->impl); | |
73 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 174 times.
|
174 | if (ret < 0) |
74 | ✗ | goto destroy_mtx; | |
75 | |||
76 | 174 | return ret; | |
77 | |||
78 | ✗ | destroy_mtx: | |
79 | ✗ | pthread_errno_if(pthread_mutex_destroy(&stmt->mtx), "pthread_mutex_destroy"); | |
80 | |||
81 | ✗ | return ret; | |
82 | } | ||
83 | |||
84 | 174 | static void prepared_stmt_destroy(struct prepared_stmt *stmt) | |
85 | { | ||
86 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 174 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
174 | pthread_errno_if(pthread_mutex_destroy(&stmt->mtx), "pthread_mutex_destroy"); |
87 | 174 | sqlite_finalize(stmt->impl); | |
88 | 174 | } | |
89 | |||
90 | 36775 | static int prepared_stmt_lock(struct prepared_stmt *stmt) | |
91 | { | ||
92 | 36775 | int ret = pthread_mutex_lock(&stmt->mtx); | |
93 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 36775 times.
|
36775 | if (ret) { |
94 | ✗ | pthread_errno(ret, "pthread_mutex_unlock"); | |
95 | ✗ | return ret; | |
96 | } | ||
97 | 36775 | return ret; | |
98 | } | ||
99 | |||
100 | 36775 | static void prepared_stmt_unlock(struct prepared_stmt *stmt) | |
101 | { | ||
102 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 36775 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
36775 | pthread_errno_if(pthread_mutex_unlock(&stmt->mtx), "pthread_mutex_unlock"); |
103 | 36775 | } | |
104 | |||
105 | struct storage_sqlite { | ||
106 | sqlite3 *db; | ||
107 | |||
108 | struct prepared_stmt stmt_repo_find; | ||
109 | struct prepared_stmt stmt_repo_insert; | ||
110 | struct prepared_stmt stmt_run_insert; | ||
111 | struct prepared_stmt stmt_run_finished; | ||
112 | struct prepared_stmt stmt_get_runs; | ||
113 | struct prepared_stmt stmt_get_run_queue; | ||
114 | }; | ||
115 | |||
116 | 29 | static int storage_sqlite_upgrade_to(struct storage_sqlite *storage, size_t version) | |
117 | { | ||
118 | static const char *const fmt = "%s PRAGMA user_version = %zu;"; | ||
119 | |||
120 | 29 | const char *script = sqlite_schemas[version]; | |
121 | 29 | int ret = 0; | |
122 | |||
123 | 29 | ret = snprintf(NULL, 0, fmt, script, version + 1); | |
124 | 29 | size_t nb = (size_t)ret + 1; | |
125 | 29 | ret = 0; | |
126 | |||
127 | 29 | char *full_script = malloc(nb); | |
128 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (!full_script) { |
129 | ✗ | log_errno("malloc"); | |
130 | ✗ | return -1; | |
131 | } | ||
132 | 29 | snprintf(full_script, nb, fmt, script, version + 1); | |
133 | |||
134 | 29 | ret = sqlite_exec_as_transaction(storage->db, full_script); | |
135 | 29 | goto free; | |
136 | |||
137 | 29 | free: | |
138 | 29 | free(full_script); | |
139 | |||
140 | 29 | return ret; | |
141 | } | ||
142 | |||
143 | 29 | static int storage_sqlite_upgrade_from_to(struct storage_sqlite *storage, size_t from, size_t to) | |
144 | { | ||
145 | 29 | int ret = 0; | |
146 | |||
147 |
2/2✓ Branch 0 taken 29 times.
✓ Branch 1 taken 29 times.
|
58 | for (size_t i = from; i < to; ++i) { |
148 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
|
29 | log("Upgrading SQLite database from version %zu to version %zu\n", i, i + 1); |
149 | 29 | ret = storage_sqlite_upgrade_to(storage, i); | |
150 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (ret < 0) { |
151 | ✗ | log_err("Failed to upgrade to version %zu\n", i + 1); | |
152 | ✗ | return ret; | |
153 | } | ||
154 | } | ||
155 | |||
156 | 29 | return ret; | |
157 | } | ||
158 | |||
159 | 29 | static int storage_sqlite_upgrade(struct storage_sqlite *storage) | |
160 | { | ||
161 | 29 | unsigned int current_version = 0; | |
162 | 29 | int ret = 0; | |
163 | |||
164 | 29 | ret = sqlite_get_user_version(storage->db, ¤t_version); | |
165 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (ret < 0) |
166 | ✗ | return ret; | |
167 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
|
29 | log("SQLite database version: %u\n", current_version); |
168 | |||
169 | 29 | size_t newest_version = sizeof(sqlite_schemas) / sizeof(sqlite_schemas[0]); | |
170 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
|
29 | log("Newest database version: %zu\n", newest_version); |
171 | |||
172 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (current_version > newest_version) { |
173 | ✗ | log_err("Unknown database version: %u\n", current_version); | |
174 | ✗ | return -1; | |
175 | } | ||
176 | |||
177 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (current_version == newest_version) { |
178 | ✗ | log("SQLite database already at the newest version\n"); | |
179 | ✗ | return 0; | |
180 | } | ||
181 | |||
182 | 29 | return storage_sqlite_upgrade_from_to(storage, current_version, newest_version); | |
183 | } | ||
184 | |||
185 | 29 | static int storage_sqlite_setup(struct storage_sqlite *storage) | |
186 | { | ||
187 | 29 | int ret = 0; | |
188 | |||
189 | 29 | ret = sqlite_set_foreign_keys(storage->db); | |
190 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (ret < 0) |
191 | ✗ | return ret; | |
192 | |||
193 | 29 | ret = storage_sqlite_upgrade(storage); | |
194 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (ret < 0) |
195 | ✗ | return ret; | |
196 | |||
197 | 29 | return ret; | |
198 | } | ||
199 | |||
200 | 29 | static int storage_sqlite_prepare_statements(struct storage_sqlite *storage) | |
201 | { | ||
202 | static const char *const fmt_repo_find = "SELECT id FROM cimple_repos WHERE url = ?;"; | ||
203 | static const char *const fmt_repo_insert = | ||
204 | "INSERT INTO cimple_repos(url) VALUES (?) ON CONFLICT(url) DO NOTHING;"; | ||
205 | static const char *const fmt_run_insert = | ||
206 | "INSERT INTO cimple_runs(status, exit_code, output, repo_id, repo_rev) VALUES (?, -1, x'', ?, ?) RETURNING id;"; | ||
207 | static const char *const fmt_run_finished = | ||
208 | "UPDATE cimple_runs SET status = ?, exit_code = ?, output = ? WHERE id = ?;"; | ||
209 | static const char *const fmt_get_runs = | ||
210 | "SELECT id, status, exit_code, repo_url, repo_rev FROM cimple_runs_view ORDER BY id DESC"; | ||
211 | static const char *const fmt_get_run_queue = | ||
212 | "SELECT id, status, exit_code, repo_url, repo_rev FROM cimple_runs_view WHERE status = ? ORDER BY id;"; | ||
213 | |||
214 | 29 | int ret = 0; | |
215 | |||
216 | 29 | ret = prepared_stmt_init(&storage->stmt_repo_find, storage->db, fmt_repo_find); | |
217 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (ret < 0) |
218 | ✗ | return ret; | |
219 | 29 | ret = prepared_stmt_init(&storage->stmt_repo_insert, storage->db, fmt_repo_insert); | |
220 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (ret < 0) |
221 | ✗ | goto finalize_repo_find; | |
222 | 29 | ret = prepared_stmt_init(&storage->stmt_run_insert, storage->db, fmt_run_insert); | |
223 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (ret < 0) |
224 | ✗ | goto finalize_repo_insert; | |
225 | 29 | ret = prepared_stmt_init(&storage->stmt_run_finished, storage->db, fmt_run_finished); | |
226 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (ret < 0) |
227 | ✗ | goto finalize_run_insert; | |
228 | 29 | ret = prepared_stmt_init(&storage->stmt_get_runs, storage->db, fmt_get_runs); | |
229 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (ret < 0) |
230 | ✗ | goto finalize_run_finished; | |
231 | 29 | ret = prepared_stmt_init(&storage->stmt_get_run_queue, storage->db, fmt_get_run_queue); | |
232 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (ret < 0) |
233 | ✗ | goto finalize_get_runs; | |
234 | |||
235 | 29 | return ret; | |
236 | |||
237 | ✗ | finalize_get_runs: | |
238 | ✗ | prepared_stmt_destroy(&storage->stmt_get_runs); | |
239 | ✗ | finalize_run_finished: | |
240 | ✗ | prepared_stmt_destroy(&storage->stmt_run_finished); | |
241 | ✗ | finalize_run_insert: | |
242 | ✗ | prepared_stmt_destroy(&storage->stmt_run_insert); | |
243 | ✗ | finalize_repo_insert: | |
244 | ✗ | prepared_stmt_destroy(&storage->stmt_repo_insert); | |
245 | ✗ | finalize_repo_find: | |
246 | ✗ | prepared_stmt_destroy(&storage->stmt_repo_find); | |
247 | |||
248 | ✗ | return ret; | |
249 | } | ||
250 | |||
251 | 29 | static void storage_sqlite_finalize_statements(struct storage_sqlite *storage) | |
252 | { | ||
253 | 29 | prepared_stmt_destroy(&storage->stmt_get_run_queue); | |
254 | 29 | prepared_stmt_destroy(&storage->stmt_get_runs); | |
255 | 29 | prepared_stmt_destroy(&storage->stmt_run_finished); | |
256 | 29 | prepared_stmt_destroy(&storage->stmt_run_insert); | |
257 | 29 | prepared_stmt_destroy(&storage->stmt_repo_insert); | |
258 | 29 | prepared_stmt_destroy(&storage->stmt_repo_find); | |
259 | 29 | } | |
260 | |||
261 | 29 | int storage_sqlite_create(struct storage *storage, const struct storage_settings *settings) | |
262 | { | ||
263 | 29 | int ret = 0; | |
264 | |||
265 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
|
29 | log("Using SQLite database at %s\n", settings->sqlite->path); |
266 | |||
267 | 29 | struct storage_sqlite *sqlite = malloc(sizeof(struct storage_sqlite)); | |
268 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (!sqlite) { |
269 | ✗ | log_errno("malloc"); | |
270 | ✗ | return -1; | |
271 | } | ||
272 | |||
273 | 29 | ret = sqlite_init(); | |
274 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (ret < 0) |
275 | ✗ | goto free; | |
276 | 29 | ret = sqlite_open_rw(settings->sqlite->path, &sqlite->db); | |
277 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (ret < 0) |
278 | ✗ | goto destroy; | |
279 | 29 | ret = storage_sqlite_setup(sqlite); | |
280 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (ret < 0) |
281 | ✗ | goto close; | |
282 | 29 | ret = storage_sqlite_prepare_statements(sqlite); | |
283 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (ret < 0) |
284 | ✗ | goto close; | |
285 | |||
286 | 29 | storage->sqlite = sqlite; | |
287 | 29 | return ret; | |
288 | |||
289 | ✗ | close: | |
290 | ✗ | sqlite_close(storage->sqlite->db); | |
291 | ✗ | destroy: | |
292 | ✗ | sqlite_destroy(); | |
293 | ✗ | free: | |
294 | ✗ | free(sqlite); | |
295 | |||
296 | ✗ | return ret; | |
297 | } | ||
298 | |||
299 | 29 | void storage_sqlite_destroy(struct storage *storage) | |
300 | { | ||
301 | 29 | storage_sqlite_finalize_statements(storage->sqlite); | |
302 | 29 | sqlite_close(storage->sqlite->db); | |
303 | 29 | sqlite_destroy(); | |
304 | 29 | free(storage->sqlite); | |
305 | 29 | } | |
306 | |||
307 | 9180 | static int storage_sqlite_find_repo(struct storage_sqlite *storage, const char *url) | |
308 | { | ||
309 | 9180 | struct prepared_stmt *stmt = &storage->stmt_repo_find; | |
310 | 9180 | int ret = 0; | |
311 | |||
312 | 9180 | ret = prepared_stmt_lock(stmt); | |
313 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) |
314 | ✗ | return ret; | |
315 | 9180 | ret = sqlite_bind_text(stmt->impl, 1, url); | |
316 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) |
317 | ✗ | goto reset; | |
318 | 9180 | ret = sqlite_step(stmt->impl); | |
319 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) |
320 | ✗ | goto reset; | |
321 | |||
322 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (!ret) |
323 | ✗ | goto reset; | |
324 | |||
325 | 9180 | ret = sqlite_column_int(stmt->impl, 0); | |
326 | 9180 | goto reset; | |
327 | |||
328 | 9180 | reset: | |
329 | 9180 | sqlite_reset(stmt->impl); | |
330 | 9180 | prepared_stmt_unlock(stmt); | |
331 | |||
332 | 9180 | return ret; | |
333 | } | ||
334 | |||
335 | 9180 | static int storage_sqlite_insert_repo(struct storage_sqlite *storage, const char *url) | |
336 | { | ||
337 | 9180 | struct prepared_stmt *stmt = &storage->stmt_repo_insert; | |
338 | 9180 | int ret = 0; | |
339 | |||
340 | 9180 | ret = prepared_stmt_lock(stmt); | |
341 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) |
342 | ✗ | return ret; | |
343 | 9180 | ret = sqlite_bind_text(stmt->impl, 1, url); | |
344 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) |
345 | ✗ | goto reset; | |
346 | 9180 | ret = sqlite_step(stmt->impl); | |
347 |
1/2✓ Branch 0 taken 9180 times.
✗ Branch 1 not taken.
|
9180 | if (ret < 0) |
348 | ✗ | goto reset; | |
349 | |||
350 | 9180 | reset: | |
351 | 9180 | sqlite_reset(stmt->impl); | |
352 | 9180 | prepared_stmt_unlock(stmt); | |
353 | |||
354 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) |
355 | ✗ | return ret; | |
356 | |||
357 | 9180 | return storage_sqlite_find_repo(storage, url); | |
358 | } | ||
359 | |||
360 | 9180 | static int storage_sqlite_insert_run(struct storage_sqlite *storage, int repo_id, const char *rev) | |
361 | { | ||
362 | 9180 | struct prepared_stmt *stmt = &storage->stmt_run_insert; | |
363 | 9180 | int ret = 0; | |
364 | |||
365 | 9180 | ret = prepared_stmt_lock(stmt); | |
366 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) |
367 | ✗ | return ret; | |
368 | 9180 | ret = sqlite_bind_int(stmt->impl, 1, RUN_STATUS_CREATED); | |
369 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) |
370 | ✗ | goto reset; | |
371 | 9180 | ret = sqlite_bind_int(stmt->impl, 2, repo_id); | |
372 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) |
373 | ✗ | goto reset; | |
374 | 9180 | ret = sqlite_bind_text(stmt->impl, 3, rev); | |
375 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) |
376 | ✗ | goto reset; | |
377 | 9180 | ret = sqlite_step(stmt->impl); | |
378 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) |
379 | ✗ | goto reset; | |
380 | |||
381 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (!ret) { |
382 | ✗ | ret = -1; | |
383 | ✗ | log_err("Failed to insert a run\n"); | |
384 | ✗ | goto reset; | |
385 | } | ||
386 | |||
387 | 9180 | ret = sqlite_column_int(stmt->impl, 0); | |
388 | 9180 | goto reset; | |
389 | |||
390 | 9180 | reset: | |
391 | 9180 | sqlite_reset(stmt->impl); | |
392 | 9180 | prepared_stmt_unlock(stmt); | |
393 | |||
394 | 9180 | return ret; | |
395 | } | ||
396 | |||
397 | 9180 | int storage_sqlite_run_create(struct storage *storage, const char *repo_url, const char *rev) | |
398 | { | ||
399 | 9180 | int ret = 0; | |
400 | |||
401 | 9180 | ret = storage_sqlite_insert_repo(storage->sqlite, repo_url); | |
402 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) |
403 | ✗ | return ret; | |
404 | |||
405 | 9180 | ret = storage_sqlite_insert_run(storage->sqlite, ret, rev); | |
406 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) |
407 | ✗ | return ret; | |
408 | |||
409 | 9180 | return ret; | |
410 | } | ||
411 | |||
412 | 9180 | int storage_sqlite_run_finished(struct storage *storage, int run_id, | |
413 | const struct proc_output *output) | ||
414 | { | ||
415 | 9180 | struct prepared_stmt *stmt = &storage->sqlite->stmt_run_finished; | |
416 | 9180 | int ret = 0; | |
417 | |||
418 | 9180 | ret = prepared_stmt_lock(stmt); | |
419 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) |
420 | ✗ | return ret; | |
421 | 9180 | ret = sqlite_bind_int(stmt->impl, 1, RUN_STATUS_FINISHED); | |
422 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) |
423 | ✗ | goto reset; | |
424 | 9180 | ret = sqlite_bind_int(stmt->impl, 2, output->ec); | |
425 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) |
426 | ✗ | goto reset; | |
427 | 9180 | ret = sqlite_bind_blob(stmt->impl, 3, output->data, output->data_size); | |
428 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) |
429 | ✗ | goto reset; | |
430 | 9180 | ret = sqlite_bind_int(stmt->impl, 4, run_id); | |
431 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) |
432 | ✗ | goto reset; | |
433 | 9180 | ret = sqlite_step(stmt->impl); | |
434 |
1/2✓ Branch 0 taken 9180 times.
✗ Branch 1 not taken.
|
9180 | if (ret < 0) |
435 | ✗ | goto reset; | |
436 | |||
437 | 9180 | reset: | |
438 | 9180 | sqlite_reset(stmt->impl); | |
439 | 9180 | prepared_stmt_unlock(stmt); | |
440 | |||
441 | 9180 | return ret; | |
442 | } | ||
443 | |||
444 | 9180 | static int storage_sqlite_row_to_run(struct sqlite3_stmt *stmt, struct run **run) | |
445 | { | ||
446 | 9180 | int ret = 0; | |
447 | |||
448 | 9180 | int id = sqlite_column_int(stmt, 0); | |
449 | 9180 | int status = sqlite_column_int(stmt, 1); | |
450 | 9180 | int exit_code = sqlite_column_int(stmt, 2); | |
451 | |||
452 | 9180 | char *url = NULL; | |
453 | 9180 | ret = sqlite_column_text(stmt, 3, &url); | |
454 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) |
455 | ✗ | return ret; | |
456 | |||
457 | 9180 | char *rev = NULL; | |
458 | 9180 | ret = sqlite_column_text(stmt, 4, &rev); | |
459 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) |
460 | ✗ | goto free_url; | |
461 | |||
462 | 9180 | ret = run_new(run, id, url, rev, status, exit_code); | |
463 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) |
464 | ✗ | goto free_rev; | |
465 | |||
466 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 9180 times.
|
9180 | log("Adding a run %d for repository %s to the queue\n", id, url); |
467 | |||
468 | 9180 | free_rev: | |
469 | 9180 | free(rev); | |
470 | |||
471 | 9180 | free_url: | |
472 | 9180 | free(url); | |
473 | |||
474 | 9180 | return ret; | |
475 | } | ||
476 | |||
477 | 55 | static int storage_sqlite_rows_to_runs(struct sqlite3_stmt *stmt, struct run_queue *queue) | |
478 | { | ||
479 | 55 | int ret = 0; | |
480 | |||
481 | 55 | run_queue_create(queue); | |
482 | |||
483 | 9180 | while (1) { | |
484 | 9235 | ret = sqlite_step(stmt); | |
485 |
2/2✓ Branch 0 taken 55 times.
✓ Branch 1 taken 9180 times.
|
9235 | if (!ret) |
486 | 55 | break; | |
487 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) |
488 | ✗ | goto run_queue_destroy; | |
489 | |||
490 | 9180 | struct run *run = NULL; | |
491 | |||
492 | 9180 | ret = storage_sqlite_row_to_run(stmt, &run); | |
493 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9180 times.
|
9180 | if (ret < 0) |
494 | ✗ | goto run_queue_destroy; | |
495 | |||
496 | 9180 | run_queue_add_last(queue, run); | |
497 | } | ||
498 | |||
499 | 55 | return ret; | |
500 | |||
501 | ✗ | run_queue_destroy: | |
502 | ✗ | run_queue_destroy(queue); | |
503 | |||
504 | ✗ | return ret; | |
505 | } | ||
506 | |||
507 | 26 | int storage_sqlite_get_runs(struct storage *storage, struct run_queue *queue) | |
508 | { | ||
509 | 26 | struct prepared_stmt *stmt = &storage->sqlite->stmt_get_runs; | |
510 | 26 | int ret = 0; | |
511 | |||
512 | 26 | ret = prepared_stmt_lock(stmt); | |
513 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
|
26 | if (ret < 0) |
514 | ✗ | return ret; | |
515 | 26 | ret = storage_sqlite_rows_to_runs(stmt->impl, queue); | |
516 |
1/2✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
|
26 | if (ret < 0) |
517 | ✗ | goto reset; | |
518 | |||
519 | 26 | reset: | |
520 | 26 | sqlite_reset(stmt->impl); | |
521 | 26 | prepared_stmt_unlock(stmt); | |
522 | |||
523 | 26 | return ret; | |
524 | } | ||
525 | |||
526 | 29 | int storage_sqlite_get_run_queue(struct storage *storage, struct run_queue *queue) | |
527 | { | ||
528 | 29 | struct prepared_stmt *stmt = &storage->sqlite->stmt_get_run_queue; | |
529 | 29 | int ret = 0; | |
530 | |||
531 | 29 | ret = prepared_stmt_lock(stmt); | |
532 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (ret < 0) |
533 | ✗ | return ret; | |
534 | 29 | ret = sqlite_bind_int(stmt->impl, 1, RUN_STATUS_CREATED); | |
535 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (ret < 0) |
536 | ✗ | goto reset; | |
537 | 29 | ret = storage_sqlite_rows_to_runs(stmt->impl, queue); | |
538 |
1/2✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
|
29 | if (ret < 0) |
539 | ✗ | goto reset; | |
540 | |||
541 | 29 | reset: | |
542 | 29 | sqlite_reset(stmt->impl); | |
543 | 29 | prepared_stmt_unlock(stmt); | |
544 | |||
545 | 29 | return ret; | |
546 | } | ||
547 |