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