Mercurial > sci
comparison lib/db.c @ 20:f98ea578b1ef
misc: revamp database
author | David Demelier <markand@malikania.fr> |
---|---|
date | Tue, 19 Jul 2022 21:52:42 +0200 |
parents | de4bf839b565 |
children | dd078aea5d02 |
comparison
equal
deleted
inserted
replaced
19:de4bf839b565 | 20:f98ea578b1ef |
---|---|
45 | 45 |
46 #define CHAR(v) (const char *)(v) | 46 #define CHAR(v) (const char *)(v) |
47 | 47 |
48 static sqlite3 *db; | 48 static sqlite3 *db; |
49 | 49 |
50 typedef void (*unpacker)(sqlite3_stmt *, struct db_ctx *, void *); | |
51 | |
52 struct str { | |
53 char *str; | |
54 struct str *next; | |
55 }; | |
56 | |
57 struct list { | 50 struct list { |
58 unpacker unpack; | 51 void (*unpack)(sqlite3_stmt *, void *); |
59 void *data; | 52 void *data; |
60 size_t datasz; | 53 size_t datasz; |
61 size_t elemwidth; | 54 size_t elemwidth; |
62 struct db_ctx *ctx; | |
63 }; | 55 }; |
64 | 56 |
65 static const char * | |
66 strlist_add(struct db_ctx *ctx, const char *text) | |
67 { | |
68 struct str *s, *list = ctx->handle; | |
69 | |
70 s = util_calloc(1, sizeof (*s)); | |
71 s->str = util_strdup(text); | |
72 LL_APPEND(list, s); | |
73 | |
74 return s->str; | |
75 } | |
76 | |
77 static void | 57 static void |
78 strlist_free(struct db_ctx *ctx) | 58 project_unpacker(sqlite3_stmt *stmt, void *data) |
79 { | 59 { |
80 struct str *s, *tmp, *list = ctx->handle; | 60 struct project *project = data; |
81 | 61 |
82 LL_FOREACH_SAFE(list, s, tmp) { | 62 project->id = sqlite3_column_int(stmt, 0); |
83 free(s->str); | 63 project->name = util_strdup(CHAR(sqlite3_column_text(stmt, 1))); |
84 free(s); | 64 project->desc = util_strdup(CHAR(sqlite3_column_text(stmt, 2))); |
85 } | 65 project->url = util_strdup(CHAR(sqlite3_column_text(stmt, 3))); |
86 | 66 project->script = util_strdup(CHAR(sqlite3_column_text(stmt, 4))); |
87 ctx->handle = NULL; | |
88 } | 67 } |
89 | 68 |
90 static void | 69 static void |
91 project_unpacker(sqlite3_stmt *stmt, struct db_ctx *ctx, struct project *project) | 70 worker_unpacker(sqlite3_stmt *stmt, void *data) |
92 { | 71 { |
93 project->id = sqlite3_column_int(stmt, 0); | 72 struct worker *w = data; |
94 project->name = strlist_add(ctx, CHAR(sqlite3_column_text(stmt, 1))); | 73 |
95 project->desc = strlist_add(ctx, CHAR(sqlite3_column_text(stmt, 2))); | 74 w->id = sqlite3_column_int(stmt, 0); |
96 project->url = strlist_add(ctx, CHAR(sqlite3_column_text(stmt, 3))); | 75 w->name = util_strdup(CHAR(sqlite3_column_text(stmt, 1))); |
97 project->script = strlist_add(ctx, CHAR(sqlite3_column_text(stmt, 4))); | 76 w->desc = util_strdup(CHAR(sqlite3_column_text(stmt, 2))); |
98 } | 77 } |
99 | 78 |
100 static void | 79 static void |
101 worker_unpacker(sqlite3_stmt *stmt, struct db_ctx *ctx, struct worker *w) | 80 job_unpacker(sqlite3_stmt *stmt, void *data) |
102 { | 81 { |
103 w->id = sqlite3_column_int(stmt, 0); | 82 struct job *job = data; |
104 w->name = strlist_add(ctx, CHAR(sqlite3_column_text(stmt, 1))); | 83 |
105 w->desc = strlist_add(ctx, CHAR(sqlite3_column_text(stmt, 2))); | |
106 } | |
107 | |
108 static void | |
109 job_unpacker(sqlite3_stmt *stmt, struct db_ctx *ctx, struct job *job) | |
110 { | |
111 job->id = sqlite3_column_int(stmt, 0); | 84 job->id = sqlite3_column_int(stmt, 0); |
112 job->tag = strlist_add(ctx, CHAR(sqlite3_column_text(stmt, 1))); | 85 job->tag = util_strdup(CHAR(sqlite3_column_text(stmt, 1))); |
113 job->project_id = sqlite3_column_int(stmt, 2); | 86 job->project_id = sqlite3_column_int(stmt, 2); |
114 } | 87 } |
115 | 88 |
116 static void | 89 static void |
117 vbind(sqlite3_stmt *stmt, const char *fmt, va_list ap) | 90 vbind(sqlite3_stmt *stmt, const char *fmt, va_list ap) |
119 for (int index = 1; *fmt; ++fmt) { | 92 for (int index = 1; *fmt; ++fmt) { |
120 switch (*fmt) { | 93 switch (*fmt) { |
121 case 'i': | 94 case 'i': |
122 sqlite3_bind_int(stmt, index++, va_arg(ap, int)); | 95 sqlite3_bind_int(stmt, index++, va_arg(ap, int)); |
123 break; | 96 break; |
97 case 'j': | |
98 sqlite3_bind_int64(stmt, index++, va_arg(ap, intmax_t)); | |
99 break; | |
124 case 's': | 100 case 's': |
125 sqlite3_bind_text(stmt, index++, va_arg(ap, const char *), -1, SQLITE_STATIC); | 101 sqlite3_bind_text(stmt, index++, va_arg(ap, const char *), -1, SQLITE_STATIC); |
126 break; | 102 break; |
127 case 'z': | 103 case 'z': |
128 sqlite3_bind_int64(stmt, index++, va_arg(ap, size_t)); | 104 sqlite3_bind_int64(stmt, index++, va_arg(ap, size_t)); |
195 va_list ap; | 171 va_list ap; |
196 int step; | 172 int step; |
197 ssize_t ret = -1; | 173 ssize_t ret = -1; |
198 size_t tot = 0; | 174 size_t tot = 0; |
199 | 175 |
200 sel->ctx->handle = NULL; | |
201 | |
202 if (sqlite3_prepare(db, sql, -1, &stmt, NULL) != SQLITE_OK) | 176 if (sqlite3_prepare(db, sql, -1, &stmt, NULL) != SQLITE_OK) |
203 return log_warn("db: %s", sqlite3_errmsg(db)), -1; | 177 return log_warn("db: %s", sqlite3_errmsg(db)), -1; |
204 | 178 |
205 va_start(ap, args); | 179 va_start(ap, args); |
206 vbind(stmt, args, ap); | 180 vbind(stmt, args, ap); |
207 va_end(ap); | 181 va_end(ap); |
208 | 182 |
209 while (tot < sel->datasz && (step = sqlite3_step(stmt)) == SQLITE_ROW) | 183 while (tot < sel->datasz && (step = sqlite3_step(stmt)) == SQLITE_ROW) |
210 sel->unpack(stmt, sel->ctx, (unsigned char *)sel->data + (tot++ * sel->elemwidth)); | 184 sel->unpack(stmt, (unsigned char *)sel->data + (tot++ * sel->elemwidth)); |
211 | 185 |
212 if (step == SQLITE_OK || step == SQLITE_DONE || step == SQLITE_ROW) | 186 if (step == SQLITE_OK || step == SQLITE_DONE || step == SQLITE_ROW) |
213 ret = tot; | 187 ret = tot; |
214 else { | 188 else |
215 memset(sel->data, 0, sel->datasz * sel->elemwidth); | 189 memset(sel->data, 0, sel->datasz * sel->elemwidth); |
216 strlist_free(sel->ctx->handle); | |
217 sel->ctx->handle = NULL; | |
218 } | |
219 | 190 |
220 sqlite3_finalize(stmt); | 191 sqlite3_finalize(stmt); |
221 | 192 |
222 return ret; | 193 return ret; |
223 } | 194 } |
254 return update(CHAR(sql_project_update), "ssssi", p->name, p->desc, | 225 return update(CHAR(sql_project_update), "ssssi", p->name, p->desc, |
255 p->url, p->script, p->id); | 226 p->url, p->script, p->id); |
256 } | 227 } |
257 | 228 |
258 ssize_t | 229 ssize_t |
259 db_project_list(struct db_ctx *ctx, struct project *projects, size_t projectsz) | 230 db_project_list(struct project *projects, size_t projectsz) |
260 { | 231 { |
261 struct list sel = { | 232 struct list sel = { |
262 .unpack = (unpacker)project_unpacker, | 233 .unpack = project_unpacker, |
263 .data = projects, | 234 .data = projects, |
264 .datasz = projectsz, | 235 .datasz = projectsz, |
265 .elemwidth = sizeof (*projects), | 236 .elemwidth = sizeof (*projects), |
266 .ctx = ctx | |
267 }; | 237 }; |
268 | 238 |
269 return list(&sel, CHAR(sql_project_list), "z", projectsz); | 239 return list(&sel, CHAR(sql_project_list), "z", projectsz); |
270 } | 240 } |
271 | 241 |
272 int | 242 int |
273 db_project_find(struct db_ctx *ctx, struct project *project) | 243 db_project_find(struct project *project, const char *name) |
274 { | 244 { |
275 struct list sel = { | 245 struct list sel = { |
276 .unpack = (unpacker)project_unpacker, | 246 .unpack = project_unpacker, |
277 .data = project, | 247 .data = project, |
278 .datasz = 1, | 248 .datasz = 1, |
279 .elemwidth = sizeof (*project), | 249 .elemwidth = sizeof (*project), |
280 .ctx = ctx | 250 }; |
281 }; | 251 |
282 | 252 return list(&sel, CHAR(sql_project_find), "s", name) == 1 ? 0 : -1; |
283 return list(&sel, CHAR(sql_project_find), "s", project->name) == 1 ? 0 : -1; | 253 } |
284 } | 254 |
285 | 255 int |
286 int | 256 db_project_find_id(struct project *project, intmax_t id) |
287 db_project_find_id(struct db_ctx *ctx, struct project *project) | 257 { |
288 { | 258 struct list sel = { |
289 struct list sel = { | 259 .unpack = project_unpacker, |
290 .unpack = (unpacker)project_unpacker, | |
291 .data = project, | 260 .data = project, |
292 .datasz = 1, | 261 .datasz = 1, |
293 .elemwidth = sizeof (*project), | 262 .elemwidth = sizeof (*project), |
294 .ctx = ctx | 263 }; |
295 }; | 264 |
296 | 265 return list(&sel, CHAR(sql_project_find_id), "i", id) == 1 ? 0 : -1; |
297 return list(&sel, CHAR(sql_project_find_id), "i", project->id) == 1 ? 0 : -1; | |
298 } | 266 } |
299 | 267 |
300 int | 268 int |
301 db_worker_add(struct worker *wk) | 269 db_worker_add(struct worker *wk) |
302 { | 270 { |
304 | 272 |
305 return (wk->id = insert(CHAR(sql_worker_add), "ss", wk->name, wk->desc)) < 0 ? -1 : 0; | 273 return (wk->id = insert(CHAR(sql_worker_add), "ss", wk->name, wk->desc)) < 0 ? -1 : 0; |
306 } | 274 } |
307 | 275 |
308 ssize_t | 276 ssize_t |
309 db_worker_list(struct db_ctx *ctx, struct worker *wk, size_t wksz) | 277 db_worker_list(struct worker *wk, size_t wksz) |
310 { | 278 { |
311 assert(ctx); | |
312 assert(wk); | 279 assert(wk); |
313 | 280 |
314 struct list sel = { | 281 struct list sel = { |
315 .unpack = (unpacker)worker_unpacker, | 282 .unpack = worker_unpacker, |
316 .data = wk, | 283 .data = wk, |
317 .datasz = wksz, | 284 .datasz = wksz, |
318 .elemwidth = sizeof (*wk), | 285 .elemwidth = sizeof (*wk), |
319 .ctx = ctx | |
320 }; | 286 }; |
321 | 287 |
322 return list(&sel, CHAR(sql_worker_list), "z", wksz); | 288 return list(&sel, CHAR(sql_worker_list), "z", wksz); |
323 } | 289 } |
324 | 290 |
325 int | 291 int |
326 db_worker_find(struct db_ctx *ctx, struct worker *wk) | 292 db_worker_find(struct worker *wk, const char *name) |
327 { | 293 { |
328 struct list sel = { | 294 struct list sel = { |
329 .unpack = (unpacker)worker_unpacker, | 295 .unpack = worker_unpacker, |
330 .data = wk, | 296 .data = wk, |
331 .datasz = 1, | 297 .datasz = 1, |
332 .elemwidth = sizeof (*wk), | 298 .elemwidth = sizeof (*wk), |
333 .ctx = ctx | 299 }; |
334 }; | 300 |
335 | 301 return list(&sel, CHAR(sql_worker_find), "s", name) == 1 ? 0 : -1; |
336 return list(&sel, CHAR(sql_worker_find), "s", wk->name) == 1 ? 0 : -1; | 302 } |
337 } | 303 |
338 | 304 int |
339 int | 305 db_worker_find_id(struct worker *wk, intmax_t id) |
340 db_worker_find_id(struct db_ctx *ctx, struct worker *wk) | 306 { |
341 { | 307 struct list sel = { |
342 struct list sel = { | 308 .unpack = worker_unpacker, |
343 .unpack = (unpacker)worker_unpacker, | |
344 .data = wk, | 309 .data = wk, |
345 .datasz = 1, | 310 .datasz = 1, |
346 .elemwidth = sizeof (*wk), | 311 .elemwidth = sizeof (*wk), |
347 .ctx = ctx | 312 }; |
348 }; | 313 |
349 | 314 return list(&sel, CHAR(sql_worker_find_id), "i", id) == 1 ? 0 : -1; |
350 return list(&sel, CHAR(sql_worker_find_id), "i", wk->id) == 1 ? 0 : -1; | |
351 } | 315 } |
352 | 316 |
353 int | 317 int |
354 db_job_add(struct job *job) | 318 db_job_add(struct job *job) |
355 { | 319 { |
358 return (job->id = insert(CHAR(sql_job_add), | 322 return (job->id = insert(CHAR(sql_job_add), |
359 "si", job->tag, job->project_id)) < 0 ? -1 : 0; | 323 "si", job->tag, job->project_id)) < 0 ? -1 : 0; |
360 } | 324 } |
361 | 325 |
362 ssize_t | 326 ssize_t |
363 db_job_todo(struct db_ctx *ctx, struct job *jobs, size_t jobsz, int worker_id) | 327 db_job_todo(struct job *jobs, size_t jobsz, int worker_id) |
364 { | 328 { |
365 assert(ctx); | |
366 assert(jobs); | 329 assert(jobs); |
367 | 330 |
368 struct list sel = { | 331 struct list sel = { |
369 .unpack = (unpacker)job_unpacker, | 332 .unpack = job_unpacker, |
370 .data = jobs, | 333 .data = jobs, |
371 .datasz = jobsz, | 334 .datasz = jobsz, |
372 .elemwidth = sizeof (*jobs), | 335 .elemwidth = sizeof (*jobs), |
373 .ctx = ctx | |
374 }; | 336 }; |
375 | 337 |
376 return list(&sel, CHAR(sql_job_todo), "iiz", worker_id, worker_id, jobsz); | 338 return list(&sel, CHAR(sql_job_todo), "iiz", worker_id, worker_id, jobsz); |
377 } | 339 } |
378 | 340 |
391 if (db) { | 353 if (db) { |
392 sqlite3_close(db); | 354 sqlite3_close(db); |
393 db = NULL; | 355 db = NULL; |
394 } | 356 } |
395 } | 357 } |
396 | |
397 void | |
398 db_ctx_finish(struct db_ctx *ctx) | |
399 { | |
400 if (ctx->handle) { | |
401 strlist_free(ctx->handle); | |
402 ctx->handle = NULL; | |
403 } | |
404 } |