]> git.ipfire.org Git - people/ms/pakfire.git/blame - src/libpakfire/db.c
db: Implement removing packages
[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>
22#include <stdlib.h>
23
26affd69
MT
24#include <sqlite3.h>
25
f5c77233 26#include <pakfire/archive.h>
33d55ab4 27#include <pakfire/db.h>
f5c77233 28#include <pakfire/file.h>
33d55ab4 29#include <pakfire/logging.h>
e49b93d1 30#include <pakfire/package.h>
18bf891d
MT
31#include <pakfire/pakfire.h>
32#include <pakfire/private.h>
1fb2b526 33#include <pakfire/relationlist.h>
e49b93d1 34#include <pakfire/repo.h>
33d55ab4
MT
35#include <pakfire/types.h>
36#include <pakfire/util.h>
37
0cb487ff
MT
38#define DATABASE_PATH PAKFIRE_PRIVATE_DIR "/packages.db"
39
5ba550fe 40#define CURRENT_SCHEMA 8
c745fb2d
MT
41#define SCHEMA_MIN_SUP 7
42
33d55ab4
MT
43struct pakfire_db {
44 Pakfire pakfire;
45 int nrefs;
77a4b3a3
MT
46
47 int mode;
26affd69
MT
48
49 sqlite3* handle;
c745fb2d 50 int schema;
33d55ab4
MT
51};
52
9c5938ea
MT
53static void logging_callback(void* data, int r, const char* msg) {
54 Pakfire pakfire = (Pakfire)data;
55
56 ERROR(pakfire, "Database Error: %s: %s\n",
57 sqlite3_errstr(r), msg);
58}
59
0076c50d
MT
60static int pakfire_db_execute(struct pakfire_db* db, const char* stmt) {
61 int r;
c745fb2d
MT
62
63 DEBUG(db->pakfire, "Executing database query: %s\n", stmt);
0076c50d
MT
64
65 do {
c745fb2d 66 r = sqlite3_exec(db->handle, stmt, NULL, NULL, NULL);
0076c50d
MT
67 } while (r == SQLITE_BUSY);
68
c745fb2d
MT
69 // Log any errors
70 if (r) {
71 ERROR(db->pakfire, "Database query failed: %s\n", sqlite3_errmsg(db->handle));
72 }
73
25753290
MT
74 return r;
75}
76
c745fb2d
MT
77static int pakfire_db_begin_transaction(struct pakfire_db* db) {
78 return pakfire_db_execute(db, "BEGIN TRANSACTION");
79}
80
81static int pakfire_db_commit(struct pakfire_db* db) {
82 return pakfire_db_execute(db, "COMMIT");
83}
84
85static int pakfire_db_rollback(struct pakfire_db* db) {
86 return pakfire_db_execute(db, "ROLLBACK");
87}
88
25753290
MT
89/*
90 This function performs any fast optimization and tries to truncate the WAL log file
91 to keep the database as compact as possible on disk.
92*/
93static void pakfire_db_optimize(struct pakfire_db* db) {
44d392ef 94 pakfire_db_execute(db, "PRAGMA optimize");
25753290 95 pakfire_db_execute(db, "PRAGMA wal_checkpoint = TRUNCATE");
0076c50d
MT
96}
97
26affd69
MT
98static void pakfire_db_free(struct pakfire_db* db) {
99 DEBUG(db->pakfire, "Releasing database at %p\n", db);
100
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
115 pakfire_free(db);
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, "
241 "epoch INTEGER, "
242 "version TEXT, "
243 "release TEXT, "
244 "arch TEXT, "
245 "groups TEXT, "
246 "filename TEXT, "
247 "size INTEGER, "
248 "inst_size INTEGER, "
249 "hash1 TEXT, "
250 "license TEXT, "
251 "summary TEXT, "
252 "description TEXT, "
253 "uuid TEXT, "
254 "vendor TEXT, "
704b3993 255 "build_host TEXT, "
704b3993
MT
256 "build_time INTEGER, "
257 "installed INTEGER, "
258 "reason TEXT, "
259 "repository TEXT"
260 ")");
261 if (r)
262 return 1;
263
264 // packages: Create index to find package by name
265 r = pakfire_db_execute(db, "CREATE INDEX IF NOT EXISTS packages_name ON packages(name)");
266 if (r)
267 return 1;
268
2359ca14
MT
269 // Create dependencies table
270 r = pakfire_db_execute(db,
271 "CREATE TABLE IF NOT EXISTS dependencies("
272 "pkg INTEGER, "
273 "type TEXT, "
46257c5f 274 "dependency TEXT, "
432a328a 275 "FOREIGN KEY (pkg) REFERENCES packages(id) ON DELETE CASCADE"
2359ca14
MT
276 ")");
277 if (r)
278 return r;
279
280 // dependencies: Add index over packages
281 r = pakfire_db_execute(db, "CREATE INDEX IF NOT EXISTS dependencies_pkg_index ON dependencies(pkg)");
282 if (r)
283 return r;
284
68036506
MT
285 // Create files table
286 r = pakfire_db_execute(db,
287 "CREATE TABLE IF NOT EXISTS files("
288 "id INTEGER PRIMARY KEY, "
289 "name TEXT, "
290 "pkg INTEGER, "
291 "size INTEGER, "
292 "type INTEGER, "
293 "config INTEGER, "
294 "datafile INTEGER, "
295 "mode INTEGER, "
296 "user TEXT, "
297 "'group' TEXT, "
298 "hash1 TEXT, "
299 "mtime INTEGER, "
46257c5f 300 "capabilities TEXT, "
432a328a 301 "FOREIGN KEY (pkg) REFERENCES packages(id) ON DELETE CASCADE"
68036506
MT
302 ")");
303 if (r)
304 return 1;
305
306 // files: Add index over packages
307 r = pakfire_db_execute(db, "CREATE INDEX IF NOT EXISTS files_pkg_index ON files(pkg)");
308 if (r)
309 return 1;
310
d83414aa
MT
311 // Create scriptlets table
312 r = pakfire_db_execute(db,
313 "CREATE TABLE IF NOT EXISTS scriptlets("
314 "id INTEGER PRIMARY KEY, "
315 "pkg INTEGER, "
265f539a 316 "type TEXT, "
46257c5f 317 "scriptlet TEXT, "
432a328a 318 "FOREIGN KEY (pkg) REFERENCES packages(id) ON DELETE CASCADE"
d83414aa
MT
319 ")");
320 if (r)
321 return 1;
322
323 // scriptlets: Add index over packages
324 r = pakfire_db_execute(db, "CREATE INDEX IF NOT EXISTS scriptlets_pkg_index ON scriptlets(pkg)");
325 if (r)
326 return 1;
327
c745fb2d
MT
328 return 0;
329}
330
46257c5f 331static int pakfire_db_migrate_to_schema_8(struct pakfire_db* db) {
5ba550fe
MT
332 // packages: Drop build_id column
333
46257c5f
MT
334 // Add foreign keys
335 // TODO sqlite doesn't support adding foreign keys to existing tables and so we would
336 // need to recreate the whole table and rename it afterwards. Annoying.
337
338 return 0;
339}
340
c745fb2d
MT
341static int pakfire_db_migrate_schema(struct pakfire_db* db) {
342 int r;
343
344 while (db->schema < CURRENT_SCHEMA) {
345 // Begin a new transaction
346 r = pakfire_db_begin_transaction(db);
347 if (r)
348 goto ROLLBACK;
349
350 switch (db->schema) {
351 // No schema exists
f168dd0c 352 case -1:
c745fb2d
MT
353 r = pakfire_db_create_schema(db);
354 if (r)
355 goto ROLLBACK;
356
357 db->schema = CURRENT_SCHEMA;
358 break;
359
46257c5f
MT
360 case 7:
361 r = pakfire_db_migrate_to_schema_8(db);
362 if (r)
363 goto ROLLBACK;
364
365 db->schema++;
366 break;
367
c745fb2d
MT
368 default:
369 ERROR(db->pakfire, "Cannot migrate database from schema %d\n", db->schema);
370 goto ROLLBACK;
371 }
372
373 // Update the schema version
374 r = pakfire_db_set_int(db, "schema", CURRENT_SCHEMA);
375 if (r)
376 goto ROLLBACK;
377
378 // All done, commit!
379 r = pakfire_db_commit(db);
380 if (r)
381 goto ROLLBACK;
382 }
383
384 return 0;
385
386ROLLBACK:
387 pakfire_db_rollback(db);
388
389 return 1;
390}
391
9c5938ea 392static int pakfire_db_setup(struct pakfire_db* db) {
25753290
MT
393 int r;
394
9c5938ea
MT
395 // Setup logging
396 sqlite3_config(SQLITE_CONFIG_LOG, logging_callback, db->pakfire);
397
46257c5f
MT
398 // Enable foreign keys
399 pakfire_db_execute(db, "PRAGMA foreign_keys = ON");
400
0076c50d
MT
401 // Make LIKE case-sensitive
402 pakfire_db_execute(db, "PRAGMA case_sensitive_like = ON");
403
c745fb2d
MT
404 // Fetch the current schema
405 db->schema = pakfire_db_get_schema(db);
406
407 // Check if the schema is recent enough
408 if (db->schema > 0 && db->schema < SCHEMA_MIN_SUP) {
409 ERROR(db->pakfire, "Database schema %d is not supported by this version of Pakfire\n",
410 db->schema);
411 return 1;
412 }
413
9c5938ea
MT
414 // Done when not in read-write mode
415 if (db->mode != PAKFIRE_DB_READWRITE)
416 return 0;
417
0076c50d
MT
418 // Disable secure delete
419 pakfire_db_execute(db, "PRAGMA secure_delete = OFF");
420
25753290
MT
421 // Set database journal to WAL
422 r = pakfire_db_execute(db, "PRAGMA journal_mode = WAL");
423 if (r != SQLITE_OK) {
424 ERROR(db->pakfire, "Could not set journal mode to WAL: %s\n",
425 sqlite3_errmsg(db->handle));
426 return 1;
427 }
428
429 // Disable autocheckpoint
430 r = sqlite3_wal_autocheckpoint(db->handle, 0);
431 if (r != SQLITE_OK) {
432 ERROR(db->pakfire, "Could not disable autocheckpoint: %s\n",
433 sqlite3_errmsg(db->handle));
434 return 1;
435 }
436
c745fb2d
MT
437 // Create or migrate schema
438 r = pakfire_db_migrate_schema(db);
439 if (r)
440 return r;
9c5938ea
MT
441
442 return 0;
443}
444
77a4b3a3 445PAKFIRE_EXPORT int pakfire_db_open(struct pakfire_db** db, Pakfire pakfire, int flags) {
26affd69
MT
446 int r = 1;
447
33d55ab4
MT
448 struct pakfire_db* o = pakfire_calloc(1, sizeof(*o));
449 if (!o)
450 return -ENOMEM;
451
452 DEBUG(pakfire, "Allocated database at %p\n", o);
453
454 o->pakfire = pakfire_ref(pakfire);
455 o->nrefs = 1;
456
26affd69
MT
457 int sqlite3_flags = 0;
458
459 // Store mode & forward it to sqlite3
460 if (flags & PAKFIRE_DB_READWRITE) {
77a4b3a3 461 o->mode = PAKFIRE_DB_READWRITE;
26affd69
MT
462 sqlite3_flags |= SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
463 } else {
77a4b3a3 464 o->mode = PAKFIRE_DB_READONLY;
26affd69
MT
465 sqlite3_flags |= SQLITE_OPEN_READONLY;
466 }
467
468 // Make the filename
469 char* path = pakfire_make_path(o->pakfire, DATABASE_PATH);
470 if (!path)
471 goto END;
472
473 // Try to open the sqlite3 database file
474 r = sqlite3_open_v2(path, &o->handle, sqlite3_flags, NULL);
475 if (r != SQLITE_OK) {
476 ERROR(pakfire, "Could not open database %s: %s\n",
477 path, sqlite3_errmsg(o->handle));
478
479 r = 1;
480 goto END;
481 }
77a4b3a3 482
9c5938ea
MT
483 // Setup the database
484 r = pakfire_db_setup(o);
485 if (r)
486 goto END;
487
33d55ab4 488 *db = o;
26affd69
MT
489 r = 0;
490
491END:
492 if (r)
493 pakfire_db_free(o);
33d55ab4 494
26affd69
MT
495 if (path)
496 free(path);
497
498 return r;
33d55ab4
MT
499}
500
18bf891d 501PAKFIRE_EXPORT struct pakfire_db* pakfire_db_ref(struct pakfire_db* db) {
33d55ab4
MT
502 db->nrefs++;
503
504 return db;
505}
506
18bf891d 507PAKFIRE_EXPORT struct 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*/
613PAKFIRE_EXPORT int pakfire_db_check(struct pakfire_db* db) {
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
MT
629// Returns the number of packages installed
630PAKFIRE_EXPORT ssize_t pakfire_db_packages(struct pakfire_db* db) {
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
1fb2b526
MT
655static int pakfire_db_add_dependencies(struct pakfire_db* db, unsigned long id, PakfirePackage pkg) {
656 sqlite3_stmt* stmt = NULL;
657 int r = 1;
658
659 const char* sql = "INSERT INTO dependencies(pkg, type, dependency) VALUES(?, ?, ?)";
660
661 // Prepare the statement
662 r = sqlite3_prepare_v2(db->handle, sql, -1, &stmt, NULL);
663 if (r) {
664 ERROR(db->pakfire, "Could not prepare SQL statement: %s: %s\n",
665 sql, sqlite3_errmsg(db->handle));
666 goto END;
667 }
668
669 const struct __relation {
670 const char* type;
671 PakfireRelationList (*func)(PakfirePackage);
672 } relations[] = {
673 { "provides", pakfire_package_get_provides },
674 { "prerequires", pakfire_package_get_prerequires },
675 { "requires", pakfire_package_get_requires },
676 { "conflicts", pakfire_package_get_conflicts },
677 { "obsoletes", pakfire_package_get_obsoletes },
678 { "recommends", pakfire_package_get_recommends },
679 { "suggests", pakfire_package_get_suggests },
680 { NULL, NULL },
681 };
682
683 for (const struct __relation* relation = relations; relation->type; relation++) {
684 PakfireRelationList list = relation->func(pkg);
685 if (!list)
686 continue;
687
b76d7b47
MT
688 for (unsigned int i = 0; i < pakfire_relationlist_size(list); i++) {
689 PakfireRelation rel = pakfire_relationlist_get(list, i);
1fb2b526
MT
690 if (!rel)
691 goto END;
692
693 char* dependency = pakfire_relation_str(rel);
694 if (!dependency) {
695 pakfire_relation_unref(rel);
696 r = 1;
697 goto END;
698 }
699
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));
705 pakfire_relation_unref(rel);
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));
714 pakfire_relation_unref(rel);
715 goto END;
716 }
717
718 // Bind dependency
719 r = sqlite3_bind_text(stmt, 3, dependency, -1, NULL);
720 if (r) {
721 ERROR(db->pakfire, "Could not bind dependency: %s\n",
722 sqlite3_errmsg(db->handle));
723 pakfire_relation_unref(rel);
724 goto END;
725 }
726
727 // Execute query
728 do {
729 r = sqlite3_step(stmt);
730 } while (r == SQLITE_BUSY);
731
732 pakfire_relation_unref(rel);
733 free(dependency);
734
735 // Reset bound values
736 sqlite3_reset(stmt);
737 }
738
739 pakfire_relationlist_unref(list);
740 }
741
742 // All okay
743 r = 0;
744
745END:
746 if (stmt)
747 sqlite3_finalize(stmt);
748
749 return r;
750}
751
f5c77233
MT
752static int pakfire_db_add_files(struct pakfire_db* db, unsigned long id, PakfireArchive archive) {
753 sqlite3_stmt* stmt = NULL;
dccd04a4 754 int r = 1;
f5c77233
MT
755
756 // Get the filelist from the archive
5e9463ec
MT
757 PakfireFilelist filelist = pakfire_archive_get_filelist(archive);
758 if (!filelist) {
f5c77233
MT
759 ERROR(db->pakfire, "Could not fetch filelist from archive\n");
760 return 1;
761 }
762
5e9463ec
MT
763 // Nothing to do if the list is empty
764 if (pakfire_filelist_is_empty(filelist))
765 goto END;
766
f5c77233
MT
767 const char* sql = "INSERT INTO files(pkg, name, size, type, config, datafile, mode, "
768 "user, 'group', hash1, mtime, capabilities) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
769
770 // Prepare the statement
771 r = sqlite3_prepare_v2(db->handle, sql, -1, &stmt, NULL);
772 if (r) {
773 ERROR(db->pakfire, "Could not prepare SQL statement: %s: %s\n",
774 sql, sqlite3_errmsg(db->handle));
775 goto END;
776 }
777
5e9463ec
MT
778 for (unsigned int i = 0; i < pakfire_filelist_size(filelist); i++) {
779 PakfireFile file = pakfire_filelist_get(filelist, i);
780
f5c77233
MT
781 // Bind package ID
782 r = sqlite3_bind_int64(stmt, 1, id);
783 if (r) {
784 ERROR(db->pakfire, "Could not bind id: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 785 pakfire_file_unref(file);
f5c77233
MT
786 goto END;
787 }
788
789 // Bind name
790 const char* name = pakfire_file_get_name(file);
791
792 r = sqlite3_bind_text(stmt, 2, name, -1, NULL);
793 if (r) {
794 ERROR(db->pakfire, "Could not bind name: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 795 pakfire_file_unref(file);
f5c77233
MT
796 goto END;
797 }
798
799 // Bind size
800 size_t size = pakfire_file_get_size(file);
801
802 r = sqlite3_bind_int64(stmt, 3, size);
803 if (r) {
804 ERROR(db->pakfire, "Could not bind size: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 805 pakfire_file_unref(file);
f5c77233
MT
806 goto END;
807 }
808
809 // Bind type - XXX this is char which isn't very helpful
810 //char type = pakfire_file_get_type(file);
811
812 r = sqlite3_bind_null(stmt, 4);
813 if (r) {
814 ERROR(db->pakfire, "Could not bind type: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 815 pakfire_file_unref(file);
f5c77233
MT
816 goto END;
817 }
818
819 // Bind config - XXX TODO
820 r = sqlite3_bind_null(stmt, 5);
821 if (r) {
822 ERROR(db->pakfire, "Could not bind config: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 823 pakfire_file_unref(file);
f5c77233
MT
824 goto END;
825 }
826
827 // Bind datafile - XXX TODO
828 r = sqlite3_bind_null(stmt, 6);
829 if (r) {
830 ERROR(db->pakfire, "Could not bind datafile: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 831 pakfire_file_unref(file);
f5c77233
MT
832 goto END;
833 }
834
835 // Bind mode
836 mode_t mode = pakfire_file_get_mode(file);
837
838 r = sqlite3_bind_int64(stmt, 7, mode);
839 if (r) {
840 ERROR(db->pakfire, "Could not bind mode: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 841 pakfire_file_unref(file);
f5c77233
MT
842 goto END;
843 }
844
845 // Bind user
846 const char* user = pakfire_file_get_user(file);
847
848 r = sqlite3_bind_text(stmt, 8, user, -1, NULL);
849 if (r) {
850 ERROR(db->pakfire, "Could not bind user: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 851 pakfire_file_unref(file);
f5c77233
MT
852 goto END;
853 }
854
855 // Bind group
856 const char* group = pakfire_file_get_group(file);
857
858 r = sqlite3_bind_text(stmt, 9, group, -1, NULL);
859 if (r) {
860 ERROR(db->pakfire, "Could not bind group: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 861 pakfire_file_unref(file);
f5c77233
MT
862 goto END;
863 }
864
865 // Bind hash1
866 const char* chksum = pakfire_file_get_chksum(file);
867
868 r = sqlite3_bind_text(stmt, 10, chksum, -1, NULL);
869 if (r) {
870 ERROR(db->pakfire, "Could not bind hash1: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 871 pakfire_file_unref(file);
f5c77233
MT
872 goto END;
873 }
874
875 // Bind mtime
876 time_t mtime = pakfire_file_get_time(file);
877
878 r = sqlite3_bind_int64(stmt, 11, mtime);
879 if (r) {
880 ERROR(db->pakfire, "Could not bind mtime: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 881 pakfire_file_unref(file);
f5c77233
MT
882 goto END;
883 }
884
885 // Bind capabilities - XXX TODO
886 r = sqlite3_bind_null(stmt, 12);
887 if (r) {
888 ERROR(db->pakfire, "Could not bind capabilities: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 889 pakfire_file_unref(file);
f5c77233
MT
890 goto END;
891 }
892
893 // Execute query
894 do {
895 r = sqlite3_step(stmt);
896 } while (r == SQLITE_BUSY);
897
898 // Move on to next file
5e9463ec 899 pakfire_file_unref(file);
f5c77233
MT
900
901 // Reset bound values
902 sqlite3_reset(stmt);
903 }
904
905 // All okay
906 r = 0;
907
908END:
909 if (stmt)
910 sqlite3_finalize(stmt);
911
5e9463ec
MT
912 pakfire_filelist_unref(filelist);
913
f5c77233
MT
914 return r;
915}
916
265f539a
MT
917static int pakfire_db_add_scriptlets(struct pakfire_db* db, unsigned long id, PakfireArchive archive) {
918 sqlite3_stmt* stmt = NULL;
919 int r = 1;
920
921 struct pakfire_scriptlet_type* scriptlet_type = PAKFIRE_SCRIPTLET_TYPES;
922 struct pakfire_scriptlet* scriptlet;
923
924 const char* sql = "INSERT INTO scriptlets(pkg, type, scriptlet) VALUES(?, ?, ?)";
925
926 // Prepare the statement
927 r = sqlite3_prepare_v2(db->handle, sql, -1, &stmt, NULL);
928 if (r) {
929 ERROR(db->pakfire, "Could not prepare SQL statement: %s: %s\n",
930 sql, sqlite3_errmsg(db->handle));
931 goto END;
932 }
933
934 while (scriptlet_type->type) {
935 // Fetch the scriptlet
936 scriptlet = pakfire_archive_get_scriptlet(archive, scriptlet_type->type);
937
938 // Go to next one if the archive does not have a scriptlet of the given type
939 if (!scriptlet) {
940 scriptlet_type++;
941 continue;
942 }
943
944 // Bind package ID
945 r = sqlite3_bind_int64(stmt, 1, id);
946 if (r) {
947 ERROR(db->pakfire, "Could not bind id: %s\n", sqlite3_errmsg(db->handle));
948 goto END;
949 }
950
951 // Bind handle
952 r = sqlite3_bind_text(stmt, 2, scriptlet_type->handle, -1, NULL);
953 if (r) {
954 ERROR(db->pakfire, "Could not bind type: %s\n", sqlite3_errmsg(db->handle));
955 goto END;
956 }
957
958 // Bind scriptlet
959 r = sqlite3_bind_text(stmt, 3, scriptlet->data, scriptlet->size, NULL);
960 if (r) {
961 ERROR(db->pakfire, "Could not bind scriptlet: %s\n", sqlite3_errmsg(db->handle));
962 goto END;
963 }
964
965 // Execute query
966 do {
967 r = sqlite3_step(stmt);
968 } while (r == SQLITE_BUSY);
969
970 // Reset bound values
971 sqlite3_reset(stmt);
972
973 scriptlet_type++;
974 }
975
976 // All okay
977 r = 0;
978
979END:
980 if (stmt)
981 sqlite3_finalize(stmt);
982
983 return r;
984}
985
f5c77233
MT
986PAKFIRE_EXPORT int pakfire_db_add_package(struct pakfire_db* db,
987 PakfirePackage pkg, PakfireArchive archive) {
e49b93d1
MT
988 sqlite3_stmt* stmt = NULL;
989 int r;
990
991 // Begin a new transaction
992 r = pakfire_db_begin_transaction(db);
993 if (r)
994 goto ROLLBACK;
995
996 const char* sql = "INSERT INTO packages(name, epoch, version, release, arch, groups, "
997 "filename, size, inst_size, hash1, license, summary, description, uuid, vendor, "
1ca6a13d
MT
998 "build_host, build_time, installed, repository, reason) VALUES(?, ?, "
999 "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, ?, ?)";
e49b93d1
MT
1000
1001 // Prepare the statement
1002 r = sqlite3_prepare_v2(db->handle, sql, strlen(sql), &stmt, NULL);
1003 if (r != SQLITE_OK) {
1004 ERROR(db->pakfire, "Could not prepare SQL statement: %s: %s\n",
1005 sql, sqlite3_errmsg(db->handle));
1006 goto ROLLBACK;
1007 }
1008
1009 // Bind name
1010 const char* name = pakfire_package_get_name(pkg);
1011
1012 r = sqlite3_bind_text(stmt, 1, name, -1, NULL);
1013 if (r) {
1014 ERROR(db->pakfire, "Could not bind name: %s\n", sqlite3_errmsg(db->handle));
1015 goto ROLLBACK;
1016 }
1017
1018 // Bind epoch
1019 unsigned long epoch = pakfire_package_get_epoch(pkg);
1020
1021 r = sqlite3_bind_int64(stmt, 2, epoch);
1022 if (r) {
1023 ERROR(db->pakfire, "Could not bind epoch: %s\n", sqlite3_errmsg(db->handle));
1024 goto ROLLBACK;
1025 }
1026
1027 // Bind version
1028 const char* version = pakfire_package_get_version(pkg);
1029
1030 r = sqlite3_bind_text(stmt, 3, version, -1, NULL);
1031 if (r) {
1032 ERROR(db->pakfire, "Could not bind version: %s\n", sqlite3_errmsg(db->handle));
1033 goto ROLLBACK;
1034 }
1035
1036 // Bind release
1037 const char* release = pakfire_package_get_release(pkg);
1038
1039 r = sqlite3_bind_text(stmt, 4, release, -1, NULL);
1040 if (r) {
1041 ERROR(db->pakfire, "Could not bind release: %s\n", sqlite3_errmsg(db->handle));
1042 goto ROLLBACK;
1043 }
1044
1045 // Bind arch
1046 const char* arch = pakfire_package_get_arch(pkg);
1047
1048 r = sqlite3_bind_text(stmt, 5, arch, -1, NULL);
1049 if (r) {
1050 ERROR(db->pakfire, "Could not bind arch: %s\n", sqlite3_errmsg(db->handle));
1051 goto ROLLBACK;
1052 }
1053
1054 // Bind groups
1055 const char* groups = pakfire_package_get_groups(pkg);
1056
1057 r = sqlite3_bind_text(stmt, 6, groups, -1, NULL);
1058 if (r) {
1059 ERROR(db->pakfire, "Could not bind groups: %s\n", sqlite3_errmsg(db->handle));
1060 goto ROLLBACK;
1061 }
1062
1063 // Bind filename
1064 const char* filename = pakfire_package_get_filename(pkg);
1065
1066 r = sqlite3_bind_text(stmt, 7, filename, -1, NULL);
1067 if (r) {
1068 ERROR(db->pakfire, "Could not bind filename: %s\n", sqlite3_errmsg(db->handle));
1069 goto ROLLBACK;
1070 }
1071
1072 // Bind size
1073 unsigned long long size = pakfire_package_get_downloadsize(pkg);
1074
1075 r = sqlite3_bind_int64(stmt, 8, size);
1076 if (r) {
1077 ERROR(db->pakfire, "Could not bind size: %s\n", sqlite3_errmsg(db->handle));
1078 goto ROLLBACK;
1079 }
1080
1081 // Bind installed size
1082 unsigned long long inst_size = pakfire_package_get_installsize(pkg);
1083
1084 r = sqlite3_bind_int64(stmt, 9, inst_size);
1085 if (r) {
1086 ERROR(db->pakfire, "Could not bind inst_size: %s\n", sqlite3_errmsg(db->handle));
1087 goto ROLLBACK;
1088 }
1089
1090 // Bind hash1
1091 const char* hash1 = pakfire_package_get_checksum(pkg);
1092
1093 r = sqlite3_bind_text(stmt, 10, hash1, -1, NULL);
1094 if (r) {
1095 ERROR(db->pakfire, "Could not bind hash1: %s\n", sqlite3_errmsg(db->handle));
1096 goto ROLLBACK;
1097 }
1098
1099 // Bind license
1100 const char* license = pakfire_package_get_license(pkg);
1101
1102 r = sqlite3_bind_text(stmt, 11, license, -1, NULL);
1103 if (r) {
1104 ERROR(db->pakfire, "Could not bind license: %s\n", sqlite3_errmsg(db->handle));
1105 goto ROLLBACK;
1106 }
1107
1108 // Bind summary
1109 const char* summary = pakfire_package_get_summary(pkg);
1110
1111 r = sqlite3_bind_text(stmt, 12, summary, -1, NULL);
1112 if (r) {
1113 ERROR(db->pakfire, "Could not bind summary: %s\n", sqlite3_errmsg(db->handle));
1114 goto ROLLBACK;
1115 }
1116
1117 // Bind description
1118 const char* description = pakfire_package_get_description(pkg);
1119
1120 r = sqlite3_bind_text(stmt, 13, description, -1, NULL);
1121 if (r) {
1122 ERROR(db->pakfire, "Could not bind description: %s\n", sqlite3_errmsg(db->handle));
1123 goto ROLLBACK;
1124 }
1125
1126 // Bind uuid
1127 const char* uuid = pakfire_package_get_uuid(pkg);
1128
1129 r = sqlite3_bind_text(stmt, 14, uuid, -1, NULL);
1130 if (r) {
1131 ERROR(db->pakfire, "Could not bind uuid: %s\n", sqlite3_errmsg(db->handle));
1132 goto ROLLBACK;
1133 }
1134
1135 // Bind vendor
1136 const char* vendor = pakfire_package_get_vendor(pkg);
1137
8f3b8280 1138 r = sqlite3_bind_text(stmt, 15, vendor, -1, NULL);
e49b93d1
MT
1139 if (r) {
1140 ERROR(db->pakfire, "Could not bind vendor: %s\n", sqlite3_errmsg(db->handle));
1141 goto ROLLBACK;
1142 }
1143
e49b93d1
MT
1144 // Bind build_host
1145 const char* buildhost = pakfire_package_get_buildhost(pkg);
1146
1147 r = sqlite3_bind_text(stmt, 16, buildhost, -1, NULL);
1148 if (r) {
1149 ERROR(db->pakfire, "Could not bind build_host: %s\n", sqlite3_errmsg(db->handle));
1150 goto ROLLBACK;
1151 }
1152
1153 // Bind build_time
1154 unsigned long long build_time = pakfire_package_get_buildtime(pkg);
1155
1156 r = sqlite3_bind_int64(stmt, 17, build_time);
1157 if (r) {
1158 ERROR(db->pakfire, "Could not bind build_time: %s\n", sqlite3_errmsg(db->handle));
1159 goto ROLLBACK;
1160 }
1161
1162 // Bind repository name
1163 PakfireRepo repo = pakfire_package_get_repo(pkg);
1164 if (repo) {
1165 const char* repo_name = pakfire_repo_get_name(repo);
1166 pakfire_repo_unref(repo);
1167
1168 r = sqlite3_bind_text(stmt, 18, repo_name, -1, NULL);
1169 if (r)
1170 goto ROLLBACK;
1171
1172 // No repository?
1173 } else {
1174 r = sqlite3_bind_null(stmt, 18);
1175 if (r)
1176 goto ROLLBACK;
1177 }
1178
1179 // XXX TODO Bind reason
1180 r = sqlite3_bind_null(stmt, 19);
1181 if (r)
1182 goto ROLLBACK;
1183
1184 // Run query
1185 do {
1186 r = sqlite3_step(stmt);
1187 } while (r == SQLITE_BUSY);
1188
1189 if (r != SQLITE_DONE) {
1190 ERROR(db->pakfire, "Could not add package to database: %s\n",
1191 sqlite3_errmsg(db->handle));
1192 goto ROLLBACK;
1193 }
1194
f5c77233
MT
1195 // Save package ID
1196 unsigned long packages_id = sqlite3_last_insert_rowid(db->handle);
1197
e49b93d1 1198 // This is done
f5c77233
MT
1199 r = sqlite3_finalize(stmt);
1200 if (r == SQLITE_OK)
1201 stmt = NULL;
1202
1fb2b526
MT
1203 // Add dependencies
1204 r = pakfire_db_add_dependencies(db, packages_id, pkg);
1205 if (r)
1206 goto ROLLBACK;
1207
f5c77233
MT
1208 // Add files
1209 r = pakfire_db_add_files(db, packages_id, archive);
1210 if (r)
1211 goto ROLLBACK;
e49b93d1 1212
265f539a
MT
1213 // Add scriptlets
1214 r = pakfire_db_add_scriptlets(db, packages_id, archive);
1215 if (r)
1216 goto ROLLBACK;
1217
e49b93d1
MT
1218 // All done, commit!
1219 r = pakfire_db_commit(db);
1220 if (r)
1221 goto ROLLBACK;
1222
1223 return 0;
1224
1225ROLLBACK:
f5c77233
MT
1226 if (stmt)
1227 sqlite3_finalize(stmt);
e49b93d1
MT
1228
1229 pakfire_db_rollback(db);
1230
1231 return 1;
eafbe2ce
MT
1232}
1233
18bf891d 1234PAKFIRE_EXPORT int pakfire_db_remove_package(struct pakfire_db* db, PakfirePackage pkg) {
432a328a
MT
1235 sqlite3_stmt* stmt = NULL;
1236 int r = 1;
1237
1238 // Fetch the package's UUID
1239 const char* uuid = pakfire_package_get_uuid(pkg);
1240 if (!uuid) {
1241 ERROR(db->pakfire, "Package has no UUID\n");
1242 goto ERROR;
1243 }
1244
1245 r = sqlite3_prepare_v2(db->handle,
1246 "DELETE FROM packages WHERE uuid = ?", -1, &stmt, NULL);
1247 if (r) {
1248 ERROR(db->pakfire, "Could not prepare SQL statement: %s\n",
1249 sqlite3_errmsg(db->handle));
1250 goto ERROR;
1251 }
1252
1253 // Bind UUID
1254 r = sqlite3_bind_text(stmt, 1, uuid, -1, NULL);
1255 if (r) {
1256 ERROR(db->pakfire, "Could not bind uuid: %s\n", sqlite3_errmsg(db->handle));
1257 return 1;
1258 }
1259
1260 // Execute query
1261 do {
1262 r = sqlite3_step(stmt);
1263 } while (r == SQLITE_BUSY);
1264
1265 // Check if we have been successful
1266 if (r != SQLITE_DONE) {
1267 ERROR(db->pakfire, "Could not delete package %s\n", uuid);
1268 r = 1;
1269 goto ERROR;
1270 }
1271
1272 r = 0;
1273
1274ERROR:
1275 if (stmt)
1276 sqlite3_finalize(stmt);
1277
1278 return r;
eafbe2ce 1279}