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 }