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