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