]> git.ipfire.org Git - people/ms/pakfire.git/blame - src/libpakfire/db.c
db: Read userinstalled packages when loading database
[people/ms/pakfire.git] / src / libpakfire / db.c
CommitLineData
33d55ab4
MT
1/*#############################################################################
2# #
3# Pakfire - The IPFire package management system #
4# Copyright (C) 2021 Pakfire development team #
5# #
6# This program is free software: you can redistribute it and/or modify #
7# it under the terms of the GNU General Public License as published by #
8# the Free Software Foundation, either version 3 of the License, or #
9# (at your option) any later version. #
10# #
11# This program is distributed in the hope that it will be useful, #
12# but WITHOUT ANY WARRANTY; without even the implied warranty of #
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14# GNU General Public License for more details. #
15# #
16# You should have received a copy of the GNU General Public License #
17# along with this program. If not, see <http://www.gnu.org/licenses/>. #
18# #
19#############################################################################*/
20
21#include <errno.h>
097b6ca6 22#include <linux/limits.h>
33d55ab4 23#include <stdlib.h>
788221bd 24#include <time.h>
33d55ab4 25
c9c03e6a 26#include <solv/solver.h>
26affd69
MT
27#include <sqlite3.h>
28
f5c77233 29#include <pakfire/archive.h>
33d55ab4 30#include <pakfire/db.h>
f5c77233 31#include <pakfire/file.h>
33d55ab4 32#include <pakfire/logging.h>
e49b93d1 33#include <pakfire/package.h>
18bf891d 34#include <pakfire/pakfire.h>
e49b93d1 35#include <pakfire/repo.h>
33d55ab4
MT
36#include <pakfire/types.h>
37#include <pakfire/util.h>
38
0cb487ff
MT
39#define DATABASE_PATH PAKFIRE_PRIVATE_DIR "/packages.db"
40
5ba550fe 41#define CURRENT_SCHEMA 8
c745fb2d
MT
42#define SCHEMA_MIN_SUP 7
43
33d55ab4
MT
44struct pakfire_db {
45 Pakfire pakfire;
46 int nrefs;
77a4b3a3 47
097b6ca6 48 char path[PATH_MAX];
77a4b3a3 49 int mode;
26affd69
MT
50
51 sqlite3* handle;
c745fb2d 52 int schema;
33d55ab4
MT
53};
54
9c5938ea
MT
55static void logging_callback(void* data, int r, const char* msg) {
56 Pakfire pakfire = (Pakfire)data;
57
58 ERROR(pakfire, "Database Error: %s: %s\n",
59 sqlite3_errstr(r), msg);
60}
61
0076c50d
MT
62static int pakfire_db_execute(struct pakfire_db* db, const char* stmt) {
63 int r;
c745fb2d
MT
64
65 DEBUG(db->pakfire, "Executing database query: %s\n", stmt);
0076c50d
MT
66
67 do {
c745fb2d 68 r = sqlite3_exec(db->handle, stmt, NULL, NULL, NULL);
0076c50d
MT
69 } while (r == SQLITE_BUSY);
70
c745fb2d
MT
71 // Log any errors
72 if (r) {
73 ERROR(db->pakfire, "Database query failed: %s\n", sqlite3_errmsg(db->handle));
74 }
75
25753290
MT
76 return r;
77}
78
c745fb2d
MT
79static int pakfire_db_begin_transaction(struct pakfire_db* db) {
80 return pakfire_db_execute(db, "BEGIN TRANSACTION");
81}
82
83static int pakfire_db_commit(struct pakfire_db* db) {
84 return pakfire_db_execute(db, "COMMIT");
85}
86
87static int pakfire_db_rollback(struct pakfire_db* db) {
88 return pakfire_db_execute(db, "ROLLBACK");
89}
90
25753290
MT
91/*
92 This function performs any fast optimization and tries to truncate the WAL log file
93 to keep the database as compact as possible on disk.
94*/
95static void pakfire_db_optimize(struct pakfire_db* db) {
44d392ef 96 pakfire_db_execute(db, "PRAGMA optimize");
25753290 97 pakfire_db_execute(db, "PRAGMA wal_checkpoint = TRUNCATE");
0076c50d
MT
98}
99
26affd69 100static void pakfire_db_free(struct pakfire_db* db) {
26affd69 101 if (db->handle) {
25753290
MT
102 // Optimize the database before it is being closed
103 pakfire_db_optimize(db);
104
105 // Close database handle
26affd69
MT
106 int r = sqlite3_close(db->handle);
107 if (r != SQLITE_OK) {
108 ERROR(db->pakfire, "Could not close database handle: %s\n",
109 sqlite3_errmsg(db->handle));
110 }
111 }
112
113 pakfire_unref(db->pakfire);
114
f0d6233d 115 free(db);
26affd69
MT
116}
117
c745fb2d
MT
118static sqlite3_value* pakfire_db_get(struct pakfire_db* db, const char* key) {
119 sqlite3_stmt* stmt = NULL;
120 sqlite3_value* val = NULL;
121 int r;
122
123 const char* sql = "SELECT val FROM settings WHERE key = ?";
124
125 // Prepare the statement
126 r = sqlite3_prepare_v2(db->handle, sql, strlen(sql), &stmt, NULL);
127 if (r != SQLITE_OK) {
128 //ERROR(db->pakfire, "Could not prepare SQL statement: %s: %s\n",
129 // sql, sqlite3_errmsg(db->handle));
130 return NULL;
131 }
132
133 // Bind key
134 r = sqlite3_bind_text(stmt, 1, key, strlen(key), NULL);
135 if (r != SQLITE_OK) {
136 ERROR(db->pakfire, "Could not bind key: %s\n", sqlite3_errmsg(db->handle));
137 goto ERROR;
138 }
139
140 // Execute the statement
141 do {
142 r = sqlite3_step(stmt);
143 } while (r == SQLITE_BUSY);
144
f168dd0c
MT
145 // We should have read a row
146 if (r != SQLITE_ROW)
147 goto ERROR;
148
c745fb2d 149 // Read value
f168dd0c 150 val = sqlite3_column_value(stmt, 0);
c745fb2d
MT
151 if (!val) {
152 ERROR(db->pakfire, "Could not read value\n");
153 goto ERROR;
154 }
155
156 // Copy value onto the heap
157 val = sqlite3_value_dup(val);
158
159ERROR:
160 if (stmt)
161 sqlite3_finalize(stmt);
162
163 return val;
164}
165
166static int pakfire_db_set_int(struct pakfire_db* db, const char* key, int val) {
167 sqlite3_stmt* stmt = NULL;
168 int r;
169
170 const char* sql = "INSERT INTO settings(key, val) VALUES(?, ?) \
171 ON CONFLICT (key) DO UPDATE SET val = excluded.val";
172
173 // Prepare statement
174 r = sqlite3_prepare_v2(db->handle, sql, strlen(sql), &stmt, NULL);
175 if (r != SQLITE_OK) {
176 ERROR(db->pakfire, "Could not prepare SQL statement: %s: %s\n",
177 sql, sqlite3_errmsg(db->handle));
178 return 1;
179 }
180
181 // Bind key
182 r = sqlite3_bind_text(stmt, 1, key, strlen(key), NULL);
183 if (r != SQLITE_OK) {
184 ERROR(db->pakfire, "Could not bind key: %s\n", sqlite3_errmsg(db->handle));
185 goto ERROR;
186 }
187
188 // Bind val
189 r = sqlite3_bind_int64(stmt, 2, val);
190 if (r != SQLITE_OK) {
191 ERROR(db->pakfire, "Could not bind val: %s\n", sqlite3_errmsg(db->handle));
192 goto ERROR;
193 }
194
195 // Execute the statement
196 do {
197 r = sqlite3_step(stmt);
198 } while (r == SQLITE_BUSY);
199
200 // Set return code
201 r = (r == SQLITE_OK);
202
203ERROR:
204 if (stmt)
205 sqlite3_finalize(stmt);
206
207 return r;
208}
209
210static int pakfire_db_get_schema(struct pakfire_db* db) {
211 sqlite3_value* value = pakfire_db_get(db, "schema");
212 if (!value)
f168dd0c 213 return -1;
c745fb2d
MT
214
215 int schema = sqlite3_value_int64(value);
216 sqlite3_value_free(value);
217
218 DEBUG(db->pakfire, "Database has schema version %d\n", schema);
219
220 return schema;
221}
222
223static int pakfire_db_create_schema(struct pakfire_db* db) {
224 int r;
225
226 // Create settings table
227 r = pakfire_db_execute(db, "CREATE TABLE IF NOT EXISTS settings(key TEXT, val TEXT)");
228 if (r)
229 return 1;
230
231 // settings: Add a unique index on key
232 r = pakfire_db_execute(db, "CREATE UNIQUE INDEX IF NOT EXISTS settings_key ON settings(key)");
233 if (r)
234 return 1;
235
704b3993
MT
236 // Create packages table
237 r = pakfire_db_execute(db,
238 "CREATE TABLE IF NOT EXISTS packages("
239 "id INTEGER PRIMARY KEY, "
240 "name TEXT, "
6ed66687 241 "evr TEXT, "
704b3993
MT
242 "arch TEXT, "
243 "groups TEXT, "
244 "filename TEXT, "
245 "size INTEGER, "
246 "inst_size INTEGER, "
247 "hash1 TEXT, "
248 "license TEXT, "
249 "summary TEXT, "
250 "description TEXT, "
251 "uuid TEXT, "
252 "vendor TEXT, "
704b3993 253 "build_host TEXT, "
704b3993
MT
254 "build_time INTEGER, "
255 "installed INTEGER, "
dc0cae14 256 "userinstalled INTEGER, "
704b3993
MT
257 "repository TEXT"
258 ")");
259 if (r)
260 return 1;
261
262 // packages: Create index to find package by name
263 r = pakfire_db_execute(db, "CREATE INDEX IF NOT EXISTS packages_name ON packages(name)");
264 if (r)
265 return 1;
266
00fd98ff
MT
267 // packages: Create unique index over UUID
268 r = pakfire_db_execute(db, "CREATE UNIQUE INDEX IF NOT EXISTS packages_uuid ON packages(uuid)");
269 if (r)
270 return 1;
271
2359ca14
MT
272 // Create dependencies table
273 r = pakfire_db_execute(db,
274 "CREATE TABLE IF NOT EXISTS dependencies("
275 "pkg INTEGER, "
276 "type TEXT, "
46257c5f 277 "dependency TEXT, "
432a328a 278 "FOREIGN KEY (pkg) REFERENCES packages(id) ON DELETE CASCADE"
2359ca14
MT
279 ")");
280 if (r)
281 return r;
282
283 // dependencies: Add index over packages
284 r = pakfire_db_execute(db, "CREATE INDEX IF NOT EXISTS dependencies_pkg_index ON dependencies(pkg)");
285 if (r)
286 return r;
287
68036506
MT
288 // Create files table
289 r = pakfire_db_execute(db,
290 "CREATE TABLE IF NOT EXISTS files("
291 "id INTEGER PRIMARY KEY, "
32485f6c 292 "path TEXT, "
68036506
MT
293 "pkg INTEGER, "
294 "size INTEGER, "
295 "type INTEGER, "
296 "config INTEGER, "
297 "datafile INTEGER, "
298 "mode INTEGER, "
299 "user TEXT, "
300 "'group' TEXT, "
301 "hash1 TEXT, "
ef4e8460 302 "ctime INTEGER, "
68036506 303 "mtime INTEGER, "
46257c5f 304 "capabilities TEXT, "
432a328a 305 "FOREIGN KEY (pkg) REFERENCES packages(id) ON DELETE CASCADE"
68036506
MT
306 ")");
307 if (r)
308 return 1;
309
310 // files: Add index over packages
311 r = pakfire_db_execute(db, "CREATE INDEX IF NOT EXISTS files_pkg_index ON files(pkg)");
312 if (r)
313 return 1;
314
d83414aa
MT
315 // Create scriptlets table
316 r = pakfire_db_execute(db,
317 "CREATE TABLE IF NOT EXISTS scriptlets("
318 "id INTEGER PRIMARY KEY, "
319 "pkg INTEGER, "
265f539a 320 "type TEXT, "
46257c5f 321 "scriptlet TEXT, "
432a328a 322 "FOREIGN KEY (pkg) REFERENCES packages(id) ON DELETE CASCADE"
d83414aa
MT
323 ")");
324 if (r)
325 return 1;
326
327 // scriptlets: Add index over packages
328 r = pakfire_db_execute(db, "CREATE INDEX IF NOT EXISTS scriptlets_pkg_index ON scriptlets(pkg)");
329 if (r)
330 return 1;
331
c745fb2d
MT
332 return 0;
333}
334
46257c5f 335static int pakfire_db_migrate_to_schema_8(struct pakfire_db* db) {
5ba550fe
MT
336 // packages: Drop build_id column
337
46257c5f
MT
338 // Add foreign keys
339 // TODO sqlite doesn't support adding foreign keys to existing tables and so we would
340 // need to recreate the whole table and rename it afterwards. Annoying.
341
342 return 0;
343}
344
c745fb2d
MT
345static int pakfire_db_migrate_schema(struct pakfire_db* db) {
346 int r;
347
348 while (db->schema < CURRENT_SCHEMA) {
349 // Begin a new transaction
350 r = pakfire_db_begin_transaction(db);
351 if (r)
352 goto ROLLBACK;
353
354 switch (db->schema) {
355 // No schema exists
f168dd0c 356 case -1:
c745fb2d
MT
357 r = pakfire_db_create_schema(db);
358 if (r)
359 goto ROLLBACK;
360
361 db->schema = CURRENT_SCHEMA;
362 break;
363
46257c5f
MT
364 case 7:
365 r = pakfire_db_migrate_to_schema_8(db);
366 if (r)
367 goto ROLLBACK;
368
369 db->schema++;
370 break;
371
c745fb2d
MT
372 default:
373 ERROR(db->pakfire, "Cannot migrate database from schema %d\n", db->schema);
374 goto ROLLBACK;
375 }
376
377 // Update the schema version
378 r = pakfire_db_set_int(db, "schema", CURRENT_SCHEMA);
379 if (r)
380 goto ROLLBACK;
381
382 // All done, commit!
383 r = pakfire_db_commit(db);
384 if (r)
385 goto ROLLBACK;
386 }
387
388 return 0;
389
390ROLLBACK:
391 pakfire_db_rollback(db);
392
393 return 1;
394}
395
9c5938ea 396static int pakfire_db_setup(struct pakfire_db* db) {
25753290
MT
397 int r;
398
9c5938ea
MT
399 // Setup logging
400 sqlite3_config(SQLITE_CONFIG_LOG, logging_callback, db->pakfire);
401
46257c5f
MT
402 // Enable foreign keys
403 pakfire_db_execute(db, "PRAGMA foreign_keys = ON");
404
0076c50d
MT
405 // Make LIKE case-sensitive
406 pakfire_db_execute(db, "PRAGMA case_sensitive_like = ON");
407
c745fb2d
MT
408 // Fetch the current schema
409 db->schema = pakfire_db_get_schema(db);
410
411 // Check if the schema is recent enough
412 if (db->schema > 0 && db->schema < SCHEMA_MIN_SUP) {
413 ERROR(db->pakfire, "Database schema %d is not supported by this version of Pakfire\n",
414 db->schema);
415 return 1;
416 }
417
9c5938ea
MT
418 // Done when not in read-write mode
419 if (db->mode != PAKFIRE_DB_READWRITE)
420 return 0;
421
0076c50d
MT
422 // Disable secure delete
423 pakfire_db_execute(db, "PRAGMA secure_delete = OFF");
424
25753290
MT
425 // Set database journal to WAL
426 r = pakfire_db_execute(db, "PRAGMA journal_mode = WAL");
427 if (r != SQLITE_OK) {
428 ERROR(db->pakfire, "Could not set journal mode to WAL: %s\n",
429 sqlite3_errmsg(db->handle));
430 return 1;
431 }
432
433 // Disable autocheckpoint
434 r = sqlite3_wal_autocheckpoint(db->handle, 0);
435 if (r != SQLITE_OK) {
436 ERROR(db->pakfire, "Could not disable autocheckpoint: %s\n",
437 sqlite3_errmsg(db->handle));
438 return 1;
439 }
440
c745fb2d
MT
441 // Create or migrate schema
442 r = pakfire_db_migrate_schema(db);
443 if (r)
444 return r;
9c5938ea
MT
445
446 return 0;
447}
448
9c78c483 449int pakfire_db_open(struct pakfire_db** db, Pakfire pakfire, int flags) {
26affd69
MT
450 int r = 1;
451
90312f5c 452 struct pakfire_db* o = calloc(1, sizeof(*o));
33d55ab4
MT
453 if (!o)
454 return -ENOMEM;
455
33d55ab4
MT
456 o->pakfire = pakfire_ref(pakfire);
457 o->nrefs = 1;
458
26affd69
MT
459 int sqlite3_flags = 0;
460
461 // Store mode & forward it to sqlite3
462 if (flags & PAKFIRE_DB_READWRITE) {
77a4b3a3 463 o->mode = PAKFIRE_DB_READWRITE;
26affd69
MT
464 sqlite3_flags |= SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
465 } else {
77a4b3a3 466 o->mode = PAKFIRE_DB_READONLY;
26affd69
MT
467 sqlite3_flags |= SQLITE_OPEN_READONLY;
468 }
469
470 // Make the filename
097b6ca6
MT
471 r = pakfire_make_path(o->pakfire, o->path, DATABASE_PATH);
472 if (r < 0)
26affd69
MT
473 goto END;
474
475 // Try to open the sqlite3 database file
097b6ca6 476 r = sqlite3_open_v2(o->path, &o->handle, sqlite3_flags, NULL);
26affd69
MT
477 if (r != SQLITE_OK) {
478 ERROR(pakfire, "Could not open database %s: %s\n",
097b6ca6 479 o->path, sqlite3_errmsg(o->handle));
26affd69
MT
480
481 r = 1;
482 goto END;
483 }
77a4b3a3 484
9c5938ea
MT
485 // Setup the database
486 r = pakfire_db_setup(o);
487 if (r)
488 goto END;
489
33d55ab4 490 *db = o;
26affd69
MT
491 r = 0;
492
493END:
494 if (r)
495 pakfire_db_free(o);
33d55ab4 496
26affd69 497 return r;
33d55ab4
MT
498}
499
9c78c483 500struct pakfire_db* pakfire_db_ref(struct pakfire_db* db) {
33d55ab4
MT
501 db->nrefs++;
502
503 return db;
504}
505
9c78c483 506struct pakfire_db* pakfire_db_unref(struct pakfire_db* db) {
33d55ab4
MT
507 if (--db->nrefs > 0)
508 return db;
509
510 pakfire_db_free(db);
511
512 return NULL;
513}
eafbe2ce 514
a1571786
MT
515static unsigned long pakfire_db_integrity_check(struct pakfire_db* db) {
516 sqlite3_stmt* stmt = NULL;
517 int r;
518
519 r = sqlite3_prepare_v2(db->handle, "PRAGMA integrity_check", -1, &stmt, NULL);
520 if (r) {
521 ERROR(db->pakfire, "Could not prepare integrity check: %s\n",
522 sqlite3_errmsg(db->handle));
523 return 1;
524 }
525
526 // Count any errors
527 unsigned long errors = 0;
528
529 while (1) {
530 do {
531 r = sqlite3_step(stmt);
532 } while (r == SQLITE_BUSY);
533
534 if (r == SQLITE_ROW) {
535 const char* error = (const char*)sqlite3_column_text(stmt, 0);
536
537 // If the message is "ok", the database has passed the check
538 if (strcmp(error, "ok") == 0)
539 continue;
540
541 // Increment error counter
542 errors++;
543
544 // Log the message
545 ERROR(db->pakfire, "%s\n", error);
546
547 // Break on anything else
548 } else
549 break;
550 }
551
552 sqlite3_finalize(stmt);
553
554 if (errors)
555 ERROR(db->pakfire, "Database integrity check failed\n");
556 else
557 INFO(db->pakfire, "Database integrity check passed\n");
558
559 return errors;
560}
561
562static unsigned long pakfire_db_foreign_key_check(struct pakfire_db* db) {
563 sqlite3_stmt* stmt = NULL;
564 int r;
565
566 r = sqlite3_prepare_v2(db->handle, "PRAGMA foreign_key_check", -1, &stmt, NULL);
567 if (r) {
568 ERROR(db->pakfire, "Could not prepare foreign key check: %s\n",
569 sqlite3_errmsg(db->handle));
570 return 1;
571 }
572
573 // Count any errors
574 unsigned long errors = 0;
575
576 while (1) {
577 do {
578 r = sqlite3_step(stmt);
579 } while (r == SQLITE_BUSY);
580
581 if (r == SQLITE_ROW) {
582 const unsigned char* table = sqlite3_column_text(stmt, 0);
583 unsigned long rowid = sqlite3_column_int64(stmt, 1);
584 const unsigned char* foreign_table = sqlite3_column_text(stmt, 2);
585 unsigned long foreign_rowid = sqlite3_column_int64(stmt, 3);
586
587 // Increment error counter
588 errors++;
589
590 // Log the message
591 ERROR(db->pakfire, "Foreign key violation found in %s, row %lu: "
592 "%lu does not exist in table %s\n", table, rowid, foreign_rowid, foreign_table);
593
594 // Break on anything else
595 } else
596 break;
597 }
598
599 sqlite3_finalize(stmt);
600
601 if (errors)
602 ERROR(db->pakfire, "Foreign key check failed\n");
603 else
604 INFO(db->pakfire, "Foreign key check passed\n");
605
606 return errors;
607}
608
609/*
610 This function performs an integrity check of the database
611*/
9c78c483 612int pakfire_db_check(struct pakfire_db* db) {
a1571786
MT
613 int r;
614
615 // Perform integrity check
616 r = pakfire_db_integrity_check(db);
617 if (r)
618 return 1;
619
620 // Perform foreign key check
621 r = pakfire_db_foreign_key_check(db);
622 if (r)
623 return 1;
624
625 return 0;
626}
627
817757f4 628// Returns the number of packages installed
9c78c483 629ssize_t pakfire_db_packages(struct pakfire_db* db) {
817757f4
MT
630 sqlite3_stmt* stmt = NULL;
631 ssize_t packages = -1;
632
633 int r = sqlite3_prepare_v2(db->handle, "SELECT COUNT(*) FROM packages", -1, &stmt, NULL);
634 if (r) {
635 ERROR(db->pakfire, "Could not prepare SQL statement: %s\n",
636 sqlite3_errmsg(db->handle));
637 return -1;
638 }
639
640 // Execute query
641 do {
642 r = sqlite3_step(stmt);
643 } while (r == SQLITE_BUSY);
644
645 if (r == SQLITE_ROW) {
646 packages = sqlite3_column_int64(stmt, 0);
647 }
648
649 sqlite3_finalize(stmt);
650
651 return packages;
652}
653
c9c03e6a
MT
654static void pakfire_db_add_userinstalled(Pakfire pakfire, const char* name) {
655 Pool* pool = pakfire_get_solv_pool(pakfire);
656
657 // Convert name to ID
658 Id id = pool_str2id(pool, name, 1);
659
660 // Append it to pooljobs
661 queue_push2(&pool->pooljobs, SOLVER_USERINSTALLED|SOLVER_SOLVABLE_NAME, id);
662}
663
1fb2b526
MT
664static int pakfire_db_add_dependencies(struct pakfire_db* db, unsigned long id, PakfirePackage pkg) {
665 sqlite3_stmt* stmt = NULL;
666 int r = 1;
667
668 const char* sql = "INSERT INTO dependencies(pkg, type, dependency) VALUES(?, ?, ?)";
669
670 // Prepare the statement
671 r = sqlite3_prepare_v2(db->handle, sql, -1, &stmt, NULL);
672 if (r) {
673 ERROR(db->pakfire, "Could not prepare SQL statement: %s: %s\n",
674 sql, sqlite3_errmsg(db->handle));
675 goto END;
676 }
677
678 const struct __relation {
679 const char* type;
452d3833 680 char** (*func)(PakfirePackage);
1fb2b526
MT
681 } relations[] = {
682 { "provides", pakfire_package_get_provides },
683 { "prerequires", pakfire_package_get_prerequires },
684 { "requires", pakfire_package_get_requires },
685 { "conflicts", pakfire_package_get_conflicts },
686 { "obsoletes", pakfire_package_get_obsoletes },
687 { "recommends", pakfire_package_get_recommends },
688 { "suggests", pakfire_package_get_suggests },
8fe2e4ba
MT
689 { "supplements", pakfire_package_get_supplements },
690 { "enhances", pakfire_package_get_enhances },
1fb2b526
MT
691 { NULL, NULL },
692 };
693
694 for (const struct __relation* relation = relations; relation->type; relation++) {
452d3833 695 char** list = relation->func(pkg);
1fb2b526
MT
696 if (!list)
697 continue;
698
452d3833 699 for (char** dep = list; *dep; dep++) {
1fb2b526
MT
700 // Bind package ID
701 r = sqlite3_bind_int64(stmt, 1, id);
702 if (r) {
703 ERROR(db->pakfire, "Could not bind id: %s\n",
704 sqlite3_errmsg(db->handle));
1fb2b526
MT
705 goto END;
706 }
707
708 // Bind type
709 r = sqlite3_bind_text(stmt, 2, relation->type, -1, NULL);
710 if (r) {
711 ERROR(db->pakfire, "Could not bind type: %s\n",
712 sqlite3_errmsg(db->handle));
1fb2b526
MT
713 goto END;
714 }
715
716 // Bind dependency
452d3833 717 r = sqlite3_bind_text(stmt, 3, *dep, -1, NULL);
1fb2b526
MT
718 if (r) {
719 ERROR(db->pakfire, "Could not bind dependency: %s\n",
720 sqlite3_errmsg(db->handle));
1fb2b526
MT
721 goto END;
722 }
723
724 // Execute query
725 do {
726 r = sqlite3_step(stmt);
727 } while (r == SQLITE_BUSY);
728
452d3833 729 free(*dep);
1fb2b526
MT
730
731 // Reset bound values
732 sqlite3_reset(stmt);
733 }
734
452d3833 735 free(list);
1fb2b526
MT
736 }
737
738 // All okay
739 r = 0;
740
741END:
742 if (stmt)
743 sqlite3_finalize(stmt);
744
745 return r;
746}
747
f5c77233
MT
748static int pakfire_db_add_files(struct pakfire_db* db, unsigned long id, PakfireArchive archive) {
749 sqlite3_stmt* stmt = NULL;
dccd04a4 750 int r = 1;
f5c77233
MT
751
752 // Get the filelist from the archive
5e9463ec
MT
753 PakfireFilelist filelist = pakfire_archive_get_filelist(archive);
754 if (!filelist) {
f5c77233
MT
755 ERROR(db->pakfire, "Could not fetch filelist from archive\n");
756 return 1;
757 }
758
5e9463ec 759 // Nothing to do if the list is empty
9a6e3e2d
MT
760 if (pakfire_filelist_is_empty(filelist)) {
761 r = 0;
5e9463ec 762 goto END;
9a6e3e2d 763 }
5e9463ec 764
32485f6c 765 const char* sql = "INSERT INTO files(pkg, path, size, type, config, datafile, mode, "
ef4e8460 766 "user, 'group', hash1, ctime, mtime, capabilities) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
f5c77233
MT
767
768 // Prepare the statement
769 r = sqlite3_prepare_v2(db->handle, sql, -1, &stmt, NULL);
770 if (r) {
771 ERROR(db->pakfire, "Could not prepare SQL statement: %s: %s\n",
772 sql, sqlite3_errmsg(db->handle));
773 goto END;
774 }
775
5e9463ec 776 for (unsigned int i = 0; i < pakfire_filelist_size(filelist); i++) {
5803b5f6 777 struct pakfire_file* file = pakfire_filelist_get(filelist, i);
5e9463ec 778
f5c77233
MT
779 // Bind package ID
780 r = sqlite3_bind_int64(stmt, 1, id);
781 if (r) {
782 ERROR(db->pakfire, "Could not bind id: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 783 pakfire_file_unref(file);
f5c77233
MT
784 goto END;
785 }
786
787 // Bind name
32485f6c 788 const char* path = pakfire_file_get_path(file);
f5c77233 789
32485f6c 790 r = sqlite3_bind_text(stmt, 2, path, -1, NULL);
f5c77233 791 if (r) {
32485f6c 792 ERROR(db->pakfire, "Could not bind path: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 793 pakfire_file_unref(file);
f5c77233
MT
794 goto END;
795 }
796
797 // Bind size
798 size_t size = pakfire_file_get_size(file);
799
800 r = sqlite3_bind_int64(stmt, 3, size);
801 if (r) {
802 ERROR(db->pakfire, "Could not bind size: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 803 pakfire_file_unref(file);
f5c77233
MT
804 goto END;
805 }
806
807 // Bind type - XXX this is char which isn't very helpful
808 //char type = pakfire_file_get_type(file);
809
810 r = sqlite3_bind_null(stmt, 4);
811 if (r) {
812 ERROR(db->pakfire, "Could not bind type: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 813 pakfire_file_unref(file);
f5c77233
MT
814 goto END;
815 }
816
817 // Bind config - XXX TODO
818 r = sqlite3_bind_null(stmt, 5);
819 if (r) {
820 ERROR(db->pakfire, "Could not bind config: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 821 pakfire_file_unref(file);
f5c77233
MT
822 goto END;
823 }
824
825 // Bind datafile - XXX TODO
826 r = sqlite3_bind_null(stmt, 6);
827 if (r) {
828 ERROR(db->pakfire, "Could not bind datafile: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 829 pakfire_file_unref(file);
f5c77233
MT
830 goto END;
831 }
832
833 // Bind mode
834 mode_t mode = pakfire_file_get_mode(file);
835
836 r = sqlite3_bind_int64(stmt, 7, mode);
837 if (r) {
838 ERROR(db->pakfire, "Could not bind mode: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 839 pakfire_file_unref(file);
f5c77233
MT
840 goto END;
841 }
842
843 // Bind user
844 const char* user = pakfire_file_get_user(file);
845
846 r = sqlite3_bind_text(stmt, 8, user, -1, NULL);
847 if (r) {
848 ERROR(db->pakfire, "Could not bind user: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 849 pakfire_file_unref(file);
f5c77233
MT
850 goto END;
851 }
852
853 // Bind group
854 const char* group = pakfire_file_get_group(file);
855
856 r = sqlite3_bind_text(stmt, 9, group, -1, NULL);
857 if (r) {
858 ERROR(db->pakfire, "Could not bind group: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 859 pakfire_file_unref(file);
f5c77233
MT
860 goto END;
861 }
862
863 // Bind hash1
864 const char* chksum = pakfire_file_get_chksum(file);
865
866 r = sqlite3_bind_text(stmt, 10, chksum, -1, NULL);
867 if (r) {
868 ERROR(db->pakfire, "Could not bind hash1: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 869 pakfire_file_unref(file);
f5c77233
MT
870 goto END;
871 }
872
ef4e8460
MT
873 // Bind ctime
874 time_t ctime = pakfire_file_get_ctime(file);
875
876 r = sqlite3_bind_int64(stmt, 11, ctime);
877 if (r) {
878 ERROR(db->pakfire, "Could not bind ctime: %s\n", sqlite3_errmsg(db->handle));
879 pakfire_file_unref(file);
880 goto END;
881 }
882
f5c77233 883 // Bind mtime
ef4e8460 884 time_t mtime = pakfire_file_get_mtime(file);
f5c77233 885
ef4e8460 886 r = sqlite3_bind_int64(stmt, 12, mtime);
f5c77233
MT
887 if (r) {
888 ERROR(db->pakfire, "Could not bind mtime: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 889 pakfire_file_unref(file);
f5c77233
MT
890 goto END;
891 }
892
893 // Bind capabilities - XXX TODO
ef4e8460 894 r = sqlite3_bind_null(stmt, 13);
f5c77233
MT
895 if (r) {
896 ERROR(db->pakfire, "Could not bind capabilities: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 897 pakfire_file_unref(file);
f5c77233
MT
898 goto END;
899 }
900
901 // Execute query
902 do {
903 r = sqlite3_step(stmt);
904 } while (r == SQLITE_BUSY);
905
906 // Move on to next file
5e9463ec 907 pakfire_file_unref(file);
f5c77233 908
5bae3112
MT
909 // Check for errors
910 if (r != SQLITE_DONE) {
911 ERROR(db->pakfire, "Could not add file to database: %s\n",
912 sqlite3_errmsg(db->handle));
913 goto END;
914 }
915
f5c77233
MT
916 // Reset bound values
917 sqlite3_reset(stmt);
918 }
919
920 // All okay
921 r = 0;
922
923END:
924 if (stmt)
925 sqlite3_finalize(stmt);
926
5e9463ec
MT
927 pakfire_filelist_unref(filelist);
928
f5c77233
MT
929 return r;
930}
931
265f539a
MT
932static int pakfire_db_add_scriptlets(struct pakfire_db* db, unsigned long id, PakfireArchive archive) {
933 sqlite3_stmt* stmt = NULL;
a0097ba2 934 size_t size;
265f539a
MT
935 int r = 1;
936
265f539a
MT
937 const char* sql = "INSERT INTO scriptlets(pkg, type, scriptlet) VALUES(?, ?, ?)";
938
939 // Prepare the statement
940 r = sqlite3_prepare_v2(db->handle, sql, -1, &stmt, NULL);
941 if (r) {
942 ERROR(db->pakfire, "Could not prepare SQL statement: %s: %s\n",
943 sql, sqlite3_errmsg(db->handle));
944 goto END;
945 }
946
a0097ba2 947 for (const char** type = pakfire_scriptlet_types; *type; type++) {
265f539a 948 // Fetch the scriptlet
106d2edd 949 struct pakfire_scriptlet* scriptlet = pakfire_archive_get_scriptlet(archive, *type);
a0097ba2 950 if (!scriptlet)
265f539a 951 continue;
265f539a
MT
952
953 // Bind package ID
954 r = sqlite3_bind_int64(stmt, 1, id);
955 if (r) {
956 ERROR(db->pakfire, "Could not bind id: %s\n", sqlite3_errmsg(db->handle));
a0097ba2 957 pakfire_scriptlet_unref(scriptlet);
265f539a
MT
958 goto END;
959 }
960
961 // Bind handle
a0097ba2 962 r = sqlite3_bind_text(stmt, 2, *type, -1, NULL);
265f539a
MT
963 if (r) {
964 ERROR(db->pakfire, "Could not bind type: %s\n", sqlite3_errmsg(db->handle));
a0097ba2 965 pakfire_scriptlet_unref(scriptlet);
265f539a
MT
966 goto END;
967 }
968
a0097ba2
MT
969 const char* data = pakfire_scriptlet_get_data(scriptlet, &size);
970
265f539a 971 // Bind scriptlet
a0097ba2 972 r = sqlite3_bind_text(stmt, 3, data, size, NULL);
265f539a
MT
973 if (r) {
974 ERROR(db->pakfire, "Could not bind scriptlet: %s\n", sqlite3_errmsg(db->handle));
a0097ba2 975 pakfire_scriptlet_unref(scriptlet);
265f539a
MT
976 goto END;
977 }
978
979 // Execute query
980 do {
981 r = sqlite3_step(stmt);
982 } while (r == SQLITE_BUSY);
983
5bae3112
MT
984 // Check for errors
985 if (r != SQLITE_DONE) {
986 ERROR(db->pakfire, "Could not add scriptlet to database: %s\n",
987 sqlite3_errmsg(db->handle));
a0097ba2 988 pakfire_scriptlet_unref(scriptlet);
5bae3112
MT
989 goto END;
990 }
991
a0097ba2
MT
992 pakfire_scriptlet_unref(scriptlet);
993
265f539a
MT
994 // Reset bound values
995 sqlite3_reset(stmt);
265f539a
MT
996 }
997
998 // All okay
999 r = 0;
1000
1001END:
1002 if (stmt)
1003 sqlite3_finalize(stmt);
1004
1005 return r;
1006}
1007
9c78c483 1008int pakfire_db_add_package(struct pakfire_db* db,
dc0cae14 1009 PakfirePackage pkg, PakfireArchive archive, int userinstalled) {
e49b93d1
MT
1010 sqlite3_stmt* stmt = NULL;
1011 int r;
1012
1013 // Begin a new transaction
1014 r = pakfire_db_begin_transaction(db);
1015 if (r)
1016 goto ROLLBACK;
1017
6ed66687
MT
1018 const char* sql = "INSERT INTO packages(name, evr, arch, groups, filename, size, "
1019 "inst_size, hash1, license, summary, description, uuid, vendor, build_host, "
dc0cae14
MT
1020 "build_time, installed, repository, userinstalled) "
1021 "VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, ?, ?)";
e49b93d1
MT
1022
1023 // Prepare the statement
1024 r = sqlite3_prepare_v2(db->handle, sql, strlen(sql), &stmt, NULL);
1025 if (r != SQLITE_OK) {
1026 ERROR(db->pakfire, "Could not prepare SQL statement: %s: %s\n",
1027 sql, sqlite3_errmsg(db->handle));
1028 goto ROLLBACK;
1029 }
1030
1031 // Bind name
1032 const char* name = pakfire_package_get_name(pkg);
1033
1034 r = sqlite3_bind_text(stmt, 1, name, -1, NULL);
1035 if (r) {
1036 ERROR(db->pakfire, "Could not bind name: %s\n", sqlite3_errmsg(db->handle));
1037 goto ROLLBACK;
1038 }
1039
6ed66687
MT
1040 // Bind evr
1041 const char* evr = pakfire_package_get_evr(pkg);
e49b93d1 1042
6ed66687 1043 r = sqlite3_bind_text(stmt, 2, evr, -1, NULL);
e49b93d1 1044 if (r) {
6ed66687 1045 ERROR(db->pakfire, "Could not bind evr: %s\n", sqlite3_errmsg(db->handle));
e49b93d1
MT
1046 goto ROLLBACK;
1047 }
1048
1049 // Bind arch
1050 const char* arch = pakfire_package_get_arch(pkg);
1051
6ed66687 1052 r = sqlite3_bind_text(stmt, 3, arch, -1, NULL);
e49b93d1
MT
1053 if (r) {
1054 ERROR(db->pakfire, "Could not bind arch: %s\n", sqlite3_errmsg(db->handle));
1055 goto ROLLBACK;
1056 }
1057
1058 // Bind groups
1eb7f40b
MT
1059 char* groups = pakfire_package_get_groups(pkg);
1060 if (groups) {
6ed66687 1061 r = sqlite3_bind_text(stmt, 4, groups, -1, NULL);
1eb7f40b
MT
1062 if (r) {
1063 ERROR(db->pakfire, "Could not bind groups: %s\n", sqlite3_errmsg(db->handle));
1064 free(groups);
1065 goto ROLLBACK;
1066 }
e49b93d1 1067
1eb7f40b
MT
1068 free(groups);
1069
1070 // No groups
1071 } else {
6ed66687 1072 r = sqlite3_bind_null(stmt, 4);
1eb7f40b
MT
1073 if (r)
1074 goto ROLLBACK;
e49b93d1
MT
1075 }
1076
1077 // Bind filename
1078 const char* filename = pakfire_package_get_filename(pkg);
1079
6ed66687 1080 r = sqlite3_bind_text(stmt, 5, filename, -1, NULL);
e49b93d1
MT
1081 if (r) {
1082 ERROR(db->pakfire, "Could not bind filename: %s\n", sqlite3_errmsg(db->handle));
1083 goto ROLLBACK;
1084 }
1085
1086 // Bind size
1087 unsigned long long size = pakfire_package_get_downloadsize(pkg);
1088
6ed66687 1089 r = sqlite3_bind_int64(stmt, 6, size);
e49b93d1
MT
1090 if (r) {
1091 ERROR(db->pakfire, "Could not bind size: %s\n", sqlite3_errmsg(db->handle));
1092 goto ROLLBACK;
1093 }
1094
1095 // Bind installed size
1096 unsigned long long inst_size = pakfire_package_get_installsize(pkg);
1097
6ed66687 1098 r = sqlite3_bind_int64(stmt, 7, inst_size);
e49b93d1
MT
1099 if (r) {
1100 ERROR(db->pakfire, "Could not bind inst_size: %s\n", sqlite3_errmsg(db->handle));
1101 goto ROLLBACK;
1102 }
1103
1104 // Bind hash1
1105 const char* hash1 = pakfire_package_get_checksum(pkg);
1106
6ed66687 1107 r = sqlite3_bind_text(stmt, 8, hash1, -1, NULL);
e49b93d1
MT
1108 if (r) {
1109 ERROR(db->pakfire, "Could not bind hash1: %s\n", sqlite3_errmsg(db->handle));
1110 goto ROLLBACK;
1111 }
1112
1113 // Bind license
1114 const char* license = pakfire_package_get_license(pkg);
1115
6ed66687 1116 r = sqlite3_bind_text(stmt, 9, license, -1, NULL);
e49b93d1
MT
1117 if (r) {
1118 ERROR(db->pakfire, "Could not bind license: %s\n", sqlite3_errmsg(db->handle));
1119 goto ROLLBACK;
1120 }
1121
1122 // Bind summary
1123 const char* summary = pakfire_package_get_summary(pkg);
1124
6ed66687 1125 r = sqlite3_bind_text(stmt, 10, summary, -1, NULL);
e49b93d1
MT
1126 if (r) {
1127 ERROR(db->pakfire, "Could not bind summary: %s\n", sqlite3_errmsg(db->handle));
1128 goto ROLLBACK;
1129 }
1130
1131 // Bind description
1132 const char* description = pakfire_package_get_description(pkg);
1133
6ed66687 1134 r = sqlite3_bind_text(stmt, 11, description, -1, NULL);
e49b93d1
MT
1135 if (r) {
1136 ERROR(db->pakfire, "Could not bind description: %s\n", sqlite3_errmsg(db->handle));
1137 goto ROLLBACK;
1138 }
1139
1140 // Bind uuid
1141 const char* uuid = pakfire_package_get_uuid(pkg);
1142
6ed66687 1143 r = sqlite3_bind_text(stmt, 12, uuid, -1, NULL);
e49b93d1
MT
1144 if (r) {
1145 ERROR(db->pakfire, "Could not bind uuid: %s\n", sqlite3_errmsg(db->handle));
1146 goto ROLLBACK;
1147 }
1148
1149 // Bind vendor
1150 const char* vendor = pakfire_package_get_vendor(pkg);
1151
6ed66687 1152 r = sqlite3_bind_text(stmt, 13, vendor, -1, NULL);
e49b93d1
MT
1153 if (r) {
1154 ERROR(db->pakfire, "Could not bind vendor: %s\n", sqlite3_errmsg(db->handle));
1155 goto ROLLBACK;
1156 }
1157
e49b93d1 1158 // Bind build_host
2ffc704d 1159 const char* build_host = pakfire_package_get_build_host(pkg);
e49b93d1 1160
6ed66687 1161 r = sqlite3_bind_text(stmt, 14, build_host, -1, NULL);
e49b93d1
MT
1162 if (r) {
1163 ERROR(db->pakfire, "Could not bind build_host: %s\n", sqlite3_errmsg(db->handle));
1164 goto ROLLBACK;
1165 }
1166
1167 // Bind build_time
2ffc704d 1168 time_t build_time = pakfire_package_get_build_time(pkg);
e49b93d1 1169
6ed66687 1170 r = sqlite3_bind_int64(stmt, 15, build_time);
e49b93d1
MT
1171 if (r) {
1172 ERROR(db->pakfire, "Could not bind build_time: %s\n", sqlite3_errmsg(db->handle));
1173 goto ROLLBACK;
1174 }
1175
1176 // Bind repository name
1177 PakfireRepo repo = pakfire_package_get_repo(pkg);
1178 if (repo) {
1179 const char* repo_name = pakfire_repo_get_name(repo);
1180 pakfire_repo_unref(repo);
1181
6ed66687 1182 r = sqlite3_bind_text(stmt, 16, repo_name, -1, NULL);
e49b93d1
MT
1183 if (r)
1184 goto ROLLBACK;
1185
1186 // No repository?
1187 } else {
6ed66687 1188 r = sqlite3_bind_null(stmt, 16);
e49b93d1
MT
1189 if (r)
1190 goto ROLLBACK;
1191 }
1192
dc0cae14
MT
1193 // installed by the user?
1194 r = sqlite3_bind_int(stmt, 17, userinstalled);
1195 if (r) {
1196 ERROR(db->pakfire, "Could not bind userinstalled: %s\n", sqlite3_errmsg(db->handle));
e49b93d1 1197 goto ROLLBACK;
dc0cae14 1198 }
e49b93d1
MT
1199
1200 // Run query
1201 do {
1202 r = sqlite3_step(stmt);
1203 } while (r == SQLITE_BUSY);
1204
1205 if (r != SQLITE_DONE) {
1206 ERROR(db->pakfire, "Could not add package to database: %s\n",
1207 sqlite3_errmsg(db->handle));
1208 goto ROLLBACK;
1209 }
1210
f5c77233
MT
1211 // Save package ID
1212 unsigned long packages_id = sqlite3_last_insert_rowid(db->handle);
1213
e49b93d1 1214 // This is done
f5c77233
MT
1215 r = sqlite3_finalize(stmt);
1216 if (r == SQLITE_OK)
1217 stmt = NULL;
1218
1fb2b526
MT
1219 // Add dependencies
1220 r = pakfire_db_add_dependencies(db, packages_id, pkg);
1221 if (r)
1222 goto ROLLBACK;
1223
f5c77233
MT
1224 // Add files
1225 r = pakfire_db_add_files(db, packages_id, archive);
1226 if (r)
1227 goto ROLLBACK;
e49b93d1 1228
265f539a
MT
1229 // Add scriptlets
1230 r = pakfire_db_add_scriptlets(db, packages_id, archive);
1231 if (r)
1232 goto ROLLBACK;
1233
e49b93d1
MT
1234 // All done, commit!
1235 r = pakfire_db_commit(db);
1236 if (r)
1237 goto ROLLBACK;
1238
1239 return 0;
1240
1241ROLLBACK:
f5c77233
MT
1242 if (stmt)
1243 sqlite3_finalize(stmt);
e49b93d1
MT
1244
1245 pakfire_db_rollback(db);
1246
1247 return 1;
eafbe2ce
MT
1248}
1249
9c78c483 1250int pakfire_db_remove_package(struct pakfire_db* db, PakfirePackage pkg) {
432a328a
MT
1251 sqlite3_stmt* stmt = NULL;
1252 int r = 1;
1253
1254 // Fetch the package's UUID
1255 const char* uuid = pakfire_package_get_uuid(pkg);
1256 if (!uuid) {
1257 ERROR(db->pakfire, "Package has no UUID\n");
1258 goto ERROR;
1259 }
1260
1261 r = sqlite3_prepare_v2(db->handle,
1262 "DELETE FROM packages WHERE uuid = ?", -1, &stmt, NULL);
1263 if (r) {
1264 ERROR(db->pakfire, "Could not prepare SQL statement: %s\n",
1265 sqlite3_errmsg(db->handle));
1266 goto ERROR;
1267 }
1268
1269 // Bind UUID
1270 r = sqlite3_bind_text(stmt, 1, uuid, -1, NULL);
1271 if (r) {
1272 ERROR(db->pakfire, "Could not bind uuid: %s\n", sqlite3_errmsg(db->handle));
1273 return 1;
1274 }
1275
1276 // Execute query
1277 do {
1278 r = sqlite3_step(stmt);
1279 } while (r == SQLITE_BUSY);
1280
1281 // Check if we have been successful
1282 if (r != SQLITE_DONE) {
1283 ERROR(db->pakfire, "Could not delete package %s\n", uuid);
1284 r = 1;
1285 goto ERROR;
1286 }
1287
1288 r = 0;
1289
1290ERROR:
1291 if (stmt)
1292 sqlite3_finalize(stmt);
1293
1294 return r;
eafbe2ce 1295}
f6942b34
MT
1296
1297struct pakfire_scriptlet* pakfire_db_get_scriptlet(struct pakfire_db* db,
a0097ba2 1298 PakfirePackage pkg, const char* type) {
f6942b34
MT
1299 struct pakfire_scriptlet* scriptlet = NULL;
1300 sqlite3_stmt* stmt = NULL;
1301 int r = 1;
1302
1303 // Fetch the package's UUID
1304 const char* uuid = pakfire_package_get_uuid(pkg);
1305 if (!uuid) {
1306 ERROR(db->pakfire, "Package has no UUID\n");
1307 goto ERROR;
1308 }
1309
1310 const char* sql = "SELECT scriptlet.scriptlet FROM packages \
1311 JOIN scriptlets ON packages.id = scriptlets.pkg \
1312 WHERE packages.uuid = ? AND scriptlets.type = ?";
1313
1314 r = sqlite3_prepare_v2(db->handle, sql, strlen(sql), &stmt, NULL);
1315 if (r) {
1316 ERROR(db->pakfire, "Could not prepare SQL statement: %s %s\n",
1317 sql, sqlite3_errmsg(db->handle));
1318 goto ERROR;
1319 }
1320
1321 // Bind UUID
1322 r = sqlite3_bind_text(stmt, 1, uuid, -1, NULL);
1323 if (r) {
1324 ERROR(db->pakfire, "Could not bind uuid: %s\n", sqlite3_errmsg(db->handle));
1325 goto ERROR;
1326 }
1327
a0097ba2 1328 r = sqlite3_bind_text(stmt, 2, type, -1, NULL);
f6942b34
MT
1329 if (r) {
1330 ERROR(db->pakfire, "Could not bind type: %s\n", sqlite3_errmsg(db->handle));
1331 goto ERROR;
1332 }
1333
a0097ba2 1334 DEBUG(db->pakfire, "Searching for scriptlet for package %s of type %s\n", uuid, type);
f6942b34
MT
1335
1336 // Execute query
1337 do {
1338 r = sqlite3_step(stmt);
1339 } while (r == SQLITE_BUSY);
1340
1341 // We have some payload
1342 if (r == SQLITE_ROW) {
1343 const void* data = sqlite3_column_blob(stmt, 1);
1344 ssize_t size = sqlite3_column_bytes(stmt, 1);
1345
1346 // Create a scriptlet object
a0097ba2
MT
1347 r = pakfire_scriptlet_create(&scriptlet, db->pakfire, type, data, size);
1348 if (r)
f6942b34
MT
1349 goto ERROR;
1350 }
1351
1352ERROR:
1353 if (stmt)
1354 sqlite3_finalize(stmt);
1355
1356 return scriptlet;
1357}
361ca45f
MT
1358
1359static int pakfire_db_load_package(struct pakfire_db* db, PakfireRepo repo, sqlite3_stmt* stmt) {
1360 PakfirePackage pkg = NULL;
361ca45f
MT
1361 int r = 1;
1362
1363 // Name
1364 const char* name = (const char*)sqlite3_column_text(stmt, 0);
1365 if (!name) {
1366 ERROR(db->pakfire, "Could not read name: %s\n", sqlite3_errmsg(db->handle));
1367 goto ERROR;
1368 }
1369
6ed66687
MT
1370 // EVR
1371 const char* evr = (const char*)sqlite3_column_text(stmt, 1);
1372 if (!evr) {
1373 ERROR(db->pakfire, "Could not read evr: %s\n", sqlite3_errmsg(db->handle));
361ca45f
MT
1374 goto ERROR;
1375 }
1376
1377 // Arch
6ed66687 1378 const char* arch = (const char*)sqlite3_column_text(stmt, 2);
361ca45f
MT
1379 if (!arch) {
1380 ERROR(db->pakfire, "Could not read arch: %s\n", sqlite3_errmsg(db->handle));
1381 goto ERROR;
1382 }
1383
361ca45f 1384 // Create package
f71cc0c7 1385 pkg = pakfire_package_create(db->pakfire, repo, name, evr, arch);
361ca45f
MT
1386 if (!pkg) {
1387 ERROR(db->pakfire, "Could not create package\n");
1388 goto ERROR;
1389 }
1390
7f826034 1391 // Groups
6ed66687 1392 const char* groups = (const char*)sqlite3_column_text(stmt, 3);
7f826034
MT
1393 if (groups) {
1394 pakfire_package_set_groups(pkg, groups);
1395 }
1396
1397 // Filename
6ed66687 1398 const char* filename = (const char*)sqlite3_column_text(stmt, 4);
7f826034
MT
1399 if (filename) {
1400 pakfire_package_set_filename(pkg, filename);
1401 }
1402
1403 // Size
6ed66687 1404 size_t size = sqlite3_column_int64(stmt, 5);
7f826034
MT
1405 if (size) {
1406 pakfire_package_set_downloadsize(pkg, size);
1407 }
1408
1409 // Installed size
6ed66687 1410 size = sqlite3_column_int64(stmt, 6);
7f826034
MT
1411 if (size) {
1412 pakfire_package_set_installsize(pkg, size);
1413 }
1414
1415 // Hash 1
6ed66687 1416 const char* hash1 = (const char*)sqlite3_column_text(stmt, 7);
7f826034
MT
1417 if (hash1) {
1418 pakfire_package_set_checksum(pkg, hash1);
1419 }
1420
1421 // License
6ed66687 1422 const char* license = (const char*)sqlite3_column_text(stmt, 8);
7f826034
MT
1423 if (license) {
1424 pakfire_package_set_license(pkg, license);
1425 }
1426
1427 // Summary
6ed66687 1428 const char* summary = (const char*)sqlite3_column_text(stmt, 9);
7f826034
MT
1429 if (summary) {
1430 pakfire_package_set_summary(pkg, summary);
1431 }
1432
1433 // Description
6ed66687 1434 const char* description = (const char*)sqlite3_column_text(stmt, 10);
7f826034
MT
1435 if (description) {
1436 pakfire_package_set_description(pkg, description);
1437 }
1438
1439 // UUID
6ed66687 1440 const char* uuid = (const char*)sqlite3_column_text(stmt, 11);
7f826034
MT
1441 if (uuid) {
1442 pakfire_package_set_uuid(pkg, uuid);
1443 }
1444
1445 // Vendor
6ed66687 1446 const char* vendor = (const char*)sqlite3_column_text(stmt, 12);
7f826034
MT
1447 if (vendor) {
1448 pakfire_package_set_vendor(pkg, vendor);
1449 }
1450
1451 // Build Host
6ed66687 1452 const char* build_host = (const char*)sqlite3_column_text(stmt, 13);
7f826034 1453 if (build_host) {
2ffc704d 1454 pakfire_package_set_build_host(pkg, build_host);
7f826034
MT
1455 }
1456
1457 // Build Time
6ed66687 1458 time_t build_time = sqlite3_column_int64(stmt, 14);
7f826034 1459 if (build_time) {
2ffc704d 1460 pakfire_package_set_build_time(pkg, build_time);
7f826034
MT
1461 }
1462
af647c55 1463 // Install Time
6ed66687 1464 time_t install_time = sqlite3_column_int64(stmt, 15);
af647c55
MT
1465 if (install_time) {
1466 pakfire_package_set_install_time(pkg, install_time);
1467 }
1468
c9c03e6a
MT
1469 // installed by user?
1470 int userinstalled = sqlite3_column_int(stmt, 16);
1471 if (userinstalled)
1472 pakfire_db_add_userinstalled(db->pakfire, name);
1473
d995f7fc 1474 // Files
c9c03e6a 1475 const char* files = (const char*)sqlite3_column_text(stmt, 17);
d995f7fc 1476 if (files) {
d995f7fc
MT
1477 r = pakfire_package_set_filelist_from_string(pkg, files);
1478 if (r)
1479 goto ERROR;
1480 }
1481
24be412a
MT
1482 // Dependencies
1483
1484 const struct dependency {
1485 unsigned int field;
452d3833 1486 void (*func)(PakfirePackage pkg, const char* dep);
24be412a 1487 } dependencies[] = {
c9c03e6a
MT
1488 { 18, pakfire_package_add_provides },
1489 { 19, pakfire_package_add_prerequires },
1490 { 20, pakfire_package_add_requires },
1491 { 21, pakfire_package_add_conflicts },
1492 { 22, pakfire_package_add_obsoletes },
1493 { 23, pakfire_package_add_recommends },
1494 { 24, pakfire_package_add_suggests },
1495 { 25, pakfire_package_add_supplements },
1496 { 26, pakfire_package_add_enhances },
24be412a
MT
1497 { 0, NULL },
1498 };
1499
1500 for (const struct dependency* deps = dependencies; deps->field; deps++) {
1501 const char* relations = (const char*)sqlite3_column_text(stmt, deps->field);
1502 if (relations) {
b81a64ec 1503 pakfire_parse_deps(db->pakfire, pkg, deps->func, relations);
24be412a
MT
1504 }
1505 }
1506
361ca45f
MT
1507 // Success
1508 r = 0;
1509
1510ERROR:
361ca45f
MT
1511 if (pkg)
1512 pakfire_package_unref(pkg);
1513
1514 return r;
1515}
1516
1517int pakfire_db_load(struct pakfire_db* db, PakfireRepo repo) {
1518 sqlite3_stmt* stmt = NULL;
1519 int r = 1;
1520
1521 DEBUG(db->pakfire, "Loading package database...\n");
1522
7fe22178
MT
1523 // Drop contents of the repository
1524 pakfire_repo_clear(repo);
1525
788221bd
MT
1526 // Save starting time
1527 clock_t t_start = clock();
1528 clock_t t_end;
1529
361ca45f
MT
1530 const char* sql =
1531 "SELECT "
6ed66687
MT
1532 "name, evr, arch, groups, filename, size, inst_size, hash1, license, summary, "
1533 "description, uuid, vendor, build_host, build_time, "
c9c03e6a 1534 "strftime('%s', installed) AS installed, userinstalled, "
d995f7fc 1535 "("
32485f6c 1536 "SELECT group_concat(path, '\n') FROM files WHERE files.pkg = packages.id"
24be412a
MT
1537 ") AS files, "
1538 "("
1539 "SELECT group_concat(dependency, '\n') FROM dependencies d "
1540 "WHERE d.pkg = packages.id AND d.type = 'provides'"
1541 ") AS provides, "
1542 "("
1543 "SELECT group_concat(dependency, '\n') FROM dependencies d "
1544 "WHERE d.pkg = packages.id AND d.type = 'prerequires'"
1545 ") AS prerequires, "
1546 "("
1547 "SELECT group_concat(dependency, '\n') FROM dependencies d "
1548 "WHERE d.pkg = packages.id AND d.type = 'requires'"
1549 ") AS requires, "
1550 "("
1551 "SELECT group_concat(dependency, '\n') FROM dependencies d "
1552 "WHERE d.pkg = packages.id AND d.type = 'conflicts'"
1553 ") AS conflicts, "
1554 "("
1555 "SELECT group_concat(dependency, '\n') FROM dependencies d "
1556 "WHERE d.pkg = packages.id AND d.type = 'obsoletes'"
1557 ") AS obsoletes, "
1558 "("
1559 "SELECT group_concat(dependency, '\n') FROM dependencies d "
1560 "WHERE d.pkg = packages.id AND d.type = 'recommends'"
1561 ") AS recommends, "
1562 "("
1563 "SELECT group_concat(dependency, '\n') FROM dependencies d "
1564 "WHERE d.pkg = packages.id AND d.type = 'suggests'"
8fe2e4ba
MT
1565 ") AS suggests, "
1566 "("
1567 "SELECT group_concat(dependency, '\n') FROM dependencies d "
1568 "WHERE d.pkg = packages.id AND d.type = 'supplements'"
1569 ") AS supplements, "
1570 "("
1571 "SELECT group_concat(dependency, '\n') FROM dependencies d "
1572 "WHERE d.pkg = packages.id AND d.type = 'enhances'"
1573 ") AS enhances "
361ca45f
MT
1574 "FROM "
1575 "packages"
1576 ";";
1577
1578 // Prepare the statement
1579 r = sqlite3_prepare_v2(db->handle, sql, strlen(sql), &stmt, NULL);
1580 if (r) {
1581 ERROR(db->pakfire, "Could not prepare SQL statement: %s %s\n",
1582 sql, sqlite3_errmsg(db->handle));
1583 goto ERROR;
1584 }
1585
1586 for (;;) {
1587 // Execute query
1588 r = sqlite3_step(stmt);
1589
1590 switch (r) {
1591 // Retry if the database was busy
1592 case SQLITE_BUSY:
1593 continue;
1594
1595 // Read a row
1596 case SQLITE_ROW:
1597 r = pakfire_db_load_package(db, repo, stmt);
1598 if (r)
1599 goto ERROR;
1600 break;
1601
1602 // All rows have been processed
1603 case SQLITE_DONE:
1604 goto END;
1605
1606 // Go to error in any other cases
1607 default:
1608 goto ERROR;
1609 }
1610 }
1611
1612END:
788221bd
MT
1613 // Save time when we finished
1614 t_end = clock();
1615
1616 DEBUG(db->pakfire, "Loading package database completed in %.4fms\n",
1617 (double)(t_end - t_start) * 1000 / CLOCKS_PER_SEC);
361ca45f 1618
05336f5e
MT
1619 // Internalize repository
1620 pakfire_repo_internalize(repo);
1621
361ca45f
MT
1622 // All done
1623 r = 0;
1624
1625ERROR:
b027597a 1626 if (r) {
361ca45f 1627 ERROR(db->pakfire, "Failed reading package database: %d\n", r);
b027597a
MT
1628 pakfire_repo_clear(repo);
1629 }
361ca45f
MT
1630
1631 if (stmt)
1632 sqlite3_finalize(stmt);
1633
1634 return r;
1635}