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