]> git.ipfire.org Git - people/ms/pakfire.git/blame - src/libpakfire/db.c
db: Add test for add_package()
[people/ms/pakfire.git] / src / libpakfire / db.c
CommitLineData
33d55ab4
MT
1/*#############################################################################
2# #
3# Pakfire - The IPFire package management system #
4# Copyright (C) 2021 Pakfire development team #
5# #
6# This program is free software: you can redistribute it and/or modify #
7# it under the terms of the GNU General Public License as published by #
8# the Free Software Foundation, either version 3 of the License, or #
9# (at your option) any later version. #
10# #
11# This program is distributed in the hope that it will be useful, #
12# but WITHOUT ANY WARRANTY; without even the implied warranty of #
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14# GNU General Public License for more details. #
15# #
16# You should have received a copy of the GNU General Public License #
17# along with this program. If not, see <http://www.gnu.org/licenses/>. #
18# #
19#############################################################################*/
20
21#include <errno.h>
22#include <stdlib.h>
23
26affd69
MT
24#include <sqlite3.h>
25
f5c77233 26#include <pakfire/archive.h>
33d55ab4 27#include <pakfire/db.h>
f5c77233 28#include <pakfire/file.h>
33d55ab4 29#include <pakfire/logging.h>
e49b93d1 30#include <pakfire/package.h>
18bf891d
MT
31#include <pakfire/pakfire.h>
32#include <pakfire/private.h>
1fb2b526 33#include <pakfire/relationlist.h>
e49b93d1 34#include <pakfire/repo.h>
33d55ab4
MT
35#include <pakfire/types.h>
36#include <pakfire/util.h>
37
0cb487ff
MT
38#define DATABASE_PATH PAKFIRE_PRIVATE_DIR "/packages.db"
39
5ba550fe 40#define CURRENT_SCHEMA 8
c745fb2d
MT
41#define SCHEMA_MIN_SUP 7
42
33d55ab4
MT
43struct pakfire_db {
44 Pakfire pakfire;
45 int nrefs;
77a4b3a3
MT
46
47 int mode;
26affd69
MT
48
49 sqlite3* handle;
c745fb2d 50 int schema;
33d55ab4
MT
51};
52
9c5938ea
MT
53static void logging_callback(void* data, int r, const char* msg) {
54 Pakfire pakfire = (Pakfire)data;
55
56 ERROR(pakfire, "Database Error: %s: %s\n",
57 sqlite3_errstr(r), msg);
58}
59
0076c50d
MT
60static int pakfire_db_execute(struct pakfire_db* db, const char* stmt) {
61 int r;
c745fb2d
MT
62
63 DEBUG(db->pakfire, "Executing database query: %s\n", stmt);
0076c50d
MT
64
65 do {
c745fb2d 66 r = sqlite3_exec(db->handle, stmt, NULL, NULL, NULL);
0076c50d
MT
67 } while (r == SQLITE_BUSY);
68
c745fb2d
MT
69 // Log any errors
70 if (r) {
71 ERROR(db->pakfire, "Database query failed: %s\n", sqlite3_errmsg(db->handle));
72 }
73
25753290
MT
74 return r;
75}
76
c745fb2d
MT
77static int pakfire_db_begin_transaction(struct pakfire_db* db) {
78 return pakfire_db_execute(db, "BEGIN TRANSACTION");
79}
80
81static int pakfire_db_commit(struct pakfire_db* db) {
82 return pakfire_db_execute(db, "COMMIT");
83}
84
85static int pakfire_db_rollback(struct pakfire_db* db) {
86 return pakfire_db_execute(db, "ROLLBACK");
87}
88
25753290
MT
89/*
90 This function performs any fast optimization and tries to truncate the WAL log file
91 to keep the database as compact as possible on disk.
92*/
93static void pakfire_db_optimize(struct pakfire_db* db) {
44d392ef 94 pakfire_db_execute(db, "PRAGMA optimize");
25753290 95 pakfire_db_execute(db, "PRAGMA wal_checkpoint = TRUNCATE");
0076c50d
MT
96}
97
26affd69
MT
98static void pakfire_db_free(struct pakfire_db* db) {
99 DEBUG(db->pakfire, "Releasing database at %p\n", db);
100
26affd69 101 if (db->handle) {
25753290
MT
102 // Optimize the database before it is being closed
103 pakfire_db_optimize(db);
104
105 // Close database handle
26affd69
MT
106 int r = sqlite3_close(db->handle);
107 if (r != SQLITE_OK) {
108 ERROR(db->pakfire, "Could not close database handle: %s\n",
109 sqlite3_errmsg(db->handle));
110 }
111 }
112
113 pakfire_unref(db->pakfire);
114
115 pakfire_free(db);
116}
117
c745fb2d
MT
118static sqlite3_value* pakfire_db_get(struct pakfire_db* db, const char* key) {
119 sqlite3_stmt* stmt = NULL;
120 sqlite3_value* val = NULL;
121 int r;
122
123 const char* sql = "SELECT val FROM settings WHERE key = ?";
124
125 // Prepare the statement
126 r = sqlite3_prepare_v2(db->handle, sql, strlen(sql), &stmt, NULL);
127 if (r != SQLITE_OK) {
128 //ERROR(db->pakfire, "Could not prepare SQL statement: %s: %s\n",
129 // sql, sqlite3_errmsg(db->handle));
130 return NULL;
131 }
132
133 // Bind key
134 r = sqlite3_bind_text(stmt, 1, key, strlen(key), NULL);
135 if (r != SQLITE_OK) {
136 ERROR(db->pakfire, "Could not bind key: %s\n", sqlite3_errmsg(db->handle));
137 goto ERROR;
138 }
139
140 // Execute the statement
141 do {
142 r = sqlite3_step(stmt);
143 } while (r == SQLITE_BUSY);
144
f168dd0c
MT
145 // We should have read a row
146 if (r != SQLITE_ROW)
147 goto ERROR;
148
c745fb2d 149 // Read value
f168dd0c 150 val = sqlite3_column_value(stmt, 0);
c745fb2d
MT
151 if (!val) {
152 ERROR(db->pakfire, "Could not read value\n");
153 goto ERROR;
154 }
155
156 // Copy value onto the heap
157 val = sqlite3_value_dup(val);
158
159ERROR:
160 if (stmt)
161 sqlite3_finalize(stmt);
162
163 return val;
164}
165
166static int pakfire_db_set_int(struct pakfire_db* db, const char* key, int val) {
167 sqlite3_stmt* stmt = NULL;
168 int r;
169
170 const char* sql = "INSERT INTO settings(key, val) VALUES(?, ?) \
171 ON CONFLICT (key) DO UPDATE SET val = excluded.val";
172
173 // Prepare statement
174 r = sqlite3_prepare_v2(db->handle, sql, strlen(sql), &stmt, NULL);
175 if (r != SQLITE_OK) {
176 ERROR(db->pakfire, "Could not prepare SQL statement: %s: %s\n",
177 sql, sqlite3_errmsg(db->handle));
178 return 1;
179 }
180
181 // Bind key
182 r = sqlite3_bind_text(stmt, 1, key, strlen(key), NULL);
183 if (r != SQLITE_OK) {
184 ERROR(db->pakfire, "Could not bind key: %s\n", sqlite3_errmsg(db->handle));
185 goto ERROR;
186 }
187
188 // Bind val
189 r = sqlite3_bind_int64(stmt, 2, val);
190 if (r != SQLITE_OK) {
191 ERROR(db->pakfire, "Could not bind val: %s\n", sqlite3_errmsg(db->handle));
192 goto ERROR;
193 }
194
195 // Execute the statement
196 do {
197 r = sqlite3_step(stmt);
198 } while (r == SQLITE_BUSY);
199
200 // Set return code
201 r = (r == SQLITE_OK);
202
203ERROR:
204 if (stmt)
205 sqlite3_finalize(stmt);
206
207 return r;
208}
209
210static int pakfire_db_get_schema(struct pakfire_db* db) {
211 sqlite3_value* value = pakfire_db_get(db, "schema");
212 if (!value)
f168dd0c 213 return -1;
c745fb2d
MT
214
215 int schema = sqlite3_value_int64(value);
216 sqlite3_value_free(value);
217
218 DEBUG(db->pakfire, "Database has schema version %d\n", schema);
219
220 return schema;
221}
222
223static int pakfire_db_create_schema(struct pakfire_db* db) {
224 int r;
225
226 // Create settings table
227 r = pakfire_db_execute(db, "CREATE TABLE IF NOT EXISTS settings(key TEXT, val TEXT)");
228 if (r)
229 return 1;
230
231 // settings: Add a unique index on key
232 r = pakfire_db_execute(db, "CREATE UNIQUE INDEX IF NOT EXISTS settings_key ON settings(key)");
233 if (r)
234 return 1;
235
704b3993
MT
236 // Create packages table
237 r = pakfire_db_execute(db,
238 "CREATE TABLE IF NOT EXISTS packages("
239 "id INTEGER PRIMARY KEY, "
240 "name TEXT, "
241 "epoch INTEGER, "
242 "version TEXT, "
243 "release TEXT, "
244 "arch TEXT, "
245 "groups TEXT, "
246 "filename TEXT, "
247 "size INTEGER, "
248 "inst_size INTEGER, "
249 "hash1 TEXT, "
250 "license TEXT, "
251 "summary TEXT, "
252 "description TEXT, "
253 "uuid TEXT, "
254 "vendor TEXT, "
704b3993 255 "build_host TEXT, "
704b3993
MT
256 "build_time INTEGER, "
257 "installed INTEGER, "
258 "reason TEXT, "
259 "repository TEXT"
260 ")");
261 if (r)
262 return 1;
263
264 // packages: Create index to find package by name
265 r = pakfire_db_execute(db, "CREATE INDEX IF NOT EXISTS packages_name ON packages(name)");
266 if (r)
267 return 1;
268
2359ca14
MT
269 // Create dependencies table
270 r = pakfire_db_execute(db,
271 "CREATE TABLE IF NOT EXISTS dependencies("
272 "pkg INTEGER, "
273 "type TEXT, "
46257c5f
MT
274 "dependency TEXT, "
275 "FOREIGN KEY (pkg) REFERENCES packages(id)"
2359ca14
MT
276 ")");
277 if (r)
278 return r;
279
280 // dependencies: Add index over packages
281 r = pakfire_db_execute(db, "CREATE INDEX IF NOT EXISTS dependencies_pkg_index ON dependencies(pkg)");
282 if (r)
283 return r;
284
68036506
MT
285 // Create files table
286 r = pakfire_db_execute(db,
287 "CREATE TABLE IF NOT EXISTS files("
288 "id INTEGER PRIMARY KEY, "
289 "name TEXT, "
290 "pkg INTEGER, "
291 "size INTEGER, "
292 "type INTEGER, "
293 "config INTEGER, "
294 "datafile INTEGER, "
295 "mode INTEGER, "
296 "user TEXT, "
297 "'group' TEXT, "
298 "hash1 TEXT, "
299 "mtime INTEGER, "
46257c5f
MT
300 "capabilities TEXT, "
301 "FOREIGN KEY (pkg) REFERENCES packages(id)"
68036506
MT
302 ")");
303 if (r)
304 return 1;
305
306 // files: Add index over packages
307 r = pakfire_db_execute(db, "CREATE INDEX IF NOT EXISTS files_pkg_index ON files(pkg)");
308 if (r)
309 return 1;
310
d83414aa
MT
311 // Create scriptlets table
312 r = pakfire_db_execute(db,
313 "CREATE TABLE IF NOT EXISTS scriptlets("
314 "id INTEGER PRIMARY KEY, "
315 "pkg INTEGER, "
265f539a 316 "type TEXT, "
46257c5f
MT
317 "scriptlet TEXT, "
318 "FOREIGN KEY (pkg) REFERENCES packages(id)"
d83414aa
MT
319 ")");
320 if (r)
321 return 1;
322
323 // scriptlets: Add index over packages
324 r = pakfire_db_execute(db, "CREATE INDEX IF NOT EXISTS scriptlets_pkg_index ON scriptlets(pkg)");
325 if (r)
326 return 1;
327
c745fb2d
MT
328 return 0;
329}
330
46257c5f 331static int pakfire_db_migrate_to_schema_8(struct pakfire_db* db) {
5ba550fe
MT
332 // packages: Drop build_id column
333
46257c5f
MT
334 // Add foreign keys
335 // TODO sqlite doesn't support adding foreign keys to existing tables and so we would
336 // need to recreate the whole table and rename it afterwards. Annoying.
337
338 return 0;
339}
340
c745fb2d
MT
341static int pakfire_db_migrate_schema(struct pakfire_db* db) {
342 int r;
343
344 while (db->schema < CURRENT_SCHEMA) {
345 // Begin a new transaction
346 r = pakfire_db_begin_transaction(db);
347 if (r)
348 goto ROLLBACK;
349
350 switch (db->schema) {
351 // No schema exists
f168dd0c 352 case -1:
c745fb2d
MT
353 r = pakfire_db_create_schema(db);
354 if (r)
355 goto ROLLBACK;
356
357 db->schema = CURRENT_SCHEMA;
358 break;
359
46257c5f
MT
360 case 7:
361 r = pakfire_db_migrate_to_schema_8(db);
362 if (r)
363 goto ROLLBACK;
364
365 db->schema++;
366 break;
367
c745fb2d
MT
368 default:
369 ERROR(db->pakfire, "Cannot migrate database from schema %d\n", db->schema);
370 goto ROLLBACK;
371 }
372
373 // Update the schema version
374 r = pakfire_db_set_int(db, "schema", CURRENT_SCHEMA);
375 if (r)
376 goto ROLLBACK;
377
378 // All done, commit!
379 r = pakfire_db_commit(db);
380 if (r)
381 goto ROLLBACK;
382 }
383
384 return 0;
385
386ROLLBACK:
387 pakfire_db_rollback(db);
388
389 return 1;
390}
391
9c5938ea 392static int pakfire_db_setup(struct pakfire_db* db) {
25753290
MT
393 int r;
394
9c5938ea
MT
395 // Setup logging
396 sqlite3_config(SQLITE_CONFIG_LOG, logging_callback, db->pakfire);
397
46257c5f
MT
398 // Enable foreign keys
399 pakfire_db_execute(db, "PRAGMA foreign_keys = ON");
400
0076c50d
MT
401 // Make LIKE case-sensitive
402 pakfire_db_execute(db, "PRAGMA case_sensitive_like = ON");
403
c745fb2d
MT
404 // Fetch the current schema
405 db->schema = pakfire_db_get_schema(db);
406
407 // Check if the schema is recent enough
408 if (db->schema > 0 && db->schema < SCHEMA_MIN_SUP) {
409 ERROR(db->pakfire, "Database schema %d is not supported by this version of Pakfire\n",
410 db->schema);
411 return 1;
412 }
413
9c5938ea
MT
414 // Done when not in read-write mode
415 if (db->mode != PAKFIRE_DB_READWRITE)
416 return 0;
417
0076c50d
MT
418 // Disable secure delete
419 pakfire_db_execute(db, "PRAGMA secure_delete = OFF");
420
25753290
MT
421 // Set database journal to WAL
422 r = pakfire_db_execute(db, "PRAGMA journal_mode = WAL");
423 if (r != SQLITE_OK) {
424 ERROR(db->pakfire, "Could not set journal mode to WAL: %s\n",
425 sqlite3_errmsg(db->handle));
426 return 1;
427 }
428
429 // Disable autocheckpoint
430 r = sqlite3_wal_autocheckpoint(db->handle, 0);
431 if (r != SQLITE_OK) {
432 ERROR(db->pakfire, "Could not disable autocheckpoint: %s\n",
433 sqlite3_errmsg(db->handle));
434 return 1;
435 }
436
c745fb2d
MT
437 // Create or migrate schema
438 r = pakfire_db_migrate_schema(db);
439 if (r)
440 return r;
9c5938ea
MT
441
442 return 0;
443}
444
77a4b3a3 445PAKFIRE_EXPORT int pakfire_db_open(struct pakfire_db** db, Pakfire pakfire, int flags) {
26affd69
MT
446 int r = 1;
447
33d55ab4
MT
448 struct pakfire_db* o = pakfire_calloc(1, sizeof(*o));
449 if (!o)
450 return -ENOMEM;
451
452 DEBUG(pakfire, "Allocated database at %p\n", o);
453
454 o->pakfire = pakfire_ref(pakfire);
455 o->nrefs = 1;
456
26affd69
MT
457 int sqlite3_flags = 0;
458
459 // Store mode & forward it to sqlite3
460 if (flags & PAKFIRE_DB_READWRITE) {
77a4b3a3 461 o->mode = PAKFIRE_DB_READWRITE;
26affd69
MT
462 sqlite3_flags |= SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
463 } else {
77a4b3a3 464 o->mode = PAKFIRE_DB_READONLY;
26affd69
MT
465 sqlite3_flags |= SQLITE_OPEN_READONLY;
466 }
467
468 // Make the filename
469 char* path = pakfire_make_path(o->pakfire, DATABASE_PATH);
470 if (!path)
471 goto END;
472
473 // Try to open the sqlite3 database file
474 r = sqlite3_open_v2(path, &o->handle, sqlite3_flags, NULL);
475 if (r != SQLITE_OK) {
476 ERROR(pakfire, "Could not open database %s: %s\n",
477 path, sqlite3_errmsg(o->handle));
478
479 r = 1;
480 goto END;
481 }
77a4b3a3 482
9c5938ea
MT
483 // Setup the database
484 r = pakfire_db_setup(o);
485 if (r)
486 goto END;
487
33d55ab4 488 *db = o;
26affd69
MT
489 r = 0;
490
491END:
492 if (r)
493 pakfire_db_free(o);
33d55ab4 494
26affd69
MT
495 if (path)
496 free(path);
497
498 return r;
33d55ab4
MT
499}
500
18bf891d 501PAKFIRE_EXPORT struct pakfire_db* pakfire_db_ref(struct pakfire_db* db) {
33d55ab4
MT
502 db->nrefs++;
503
504 return db;
505}
506
18bf891d 507PAKFIRE_EXPORT struct pakfire_db* pakfire_db_unref(struct pakfire_db* db) {
33d55ab4
MT
508 if (--db->nrefs > 0)
509 return db;
510
511 pakfire_db_free(db);
512
513 return NULL;
514}
eafbe2ce 515
a1571786
MT
516static unsigned long pakfire_db_integrity_check(struct pakfire_db* db) {
517 sqlite3_stmt* stmt = NULL;
518 int r;
519
520 r = sqlite3_prepare_v2(db->handle, "PRAGMA integrity_check", -1, &stmt, NULL);
521 if (r) {
522 ERROR(db->pakfire, "Could not prepare integrity check: %s\n",
523 sqlite3_errmsg(db->handle));
524 return 1;
525 }
526
527 // Count any errors
528 unsigned long errors = 0;
529
530 while (1) {
531 do {
532 r = sqlite3_step(stmt);
533 } while (r == SQLITE_BUSY);
534
535 if (r == SQLITE_ROW) {
536 const char* error = (const char*)sqlite3_column_text(stmt, 0);
537
538 // If the message is "ok", the database has passed the check
539 if (strcmp(error, "ok") == 0)
540 continue;
541
542 // Increment error counter
543 errors++;
544
545 // Log the message
546 ERROR(db->pakfire, "%s\n", error);
547
548 // Break on anything else
549 } else
550 break;
551 }
552
553 sqlite3_finalize(stmt);
554
555 if (errors)
556 ERROR(db->pakfire, "Database integrity check failed\n");
557 else
558 INFO(db->pakfire, "Database integrity check passed\n");
559
560 return errors;
561}
562
563static unsigned long pakfire_db_foreign_key_check(struct pakfire_db* db) {
564 sqlite3_stmt* stmt = NULL;
565 int r;
566
567 r = sqlite3_prepare_v2(db->handle, "PRAGMA foreign_key_check", -1, &stmt, NULL);
568 if (r) {
569 ERROR(db->pakfire, "Could not prepare foreign key check: %s\n",
570 sqlite3_errmsg(db->handle));
571 return 1;
572 }
573
574 // Count any errors
575 unsigned long errors = 0;
576
577 while (1) {
578 do {
579 r = sqlite3_step(stmt);
580 } while (r == SQLITE_BUSY);
581
582 if (r == SQLITE_ROW) {
583 const unsigned char* table = sqlite3_column_text(stmt, 0);
584 unsigned long rowid = sqlite3_column_int64(stmt, 1);
585 const unsigned char* foreign_table = sqlite3_column_text(stmt, 2);
586 unsigned long foreign_rowid = sqlite3_column_int64(stmt, 3);
587
588 // Increment error counter
589 errors++;
590
591 // Log the message
592 ERROR(db->pakfire, "Foreign key violation found in %s, row %lu: "
593 "%lu does not exist in table %s\n", table, rowid, foreign_rowid, foreign_table);
594
595 // Break on anything else
596 } else
597 break;
598 }
599
600 sqlite3_finalize(stmt);
601
602 if (errors)
603 ERROR(db->pakfire, "Foreign key check failed\n");
604 else
605 INFO(db->pakfire, "Foreign key check passed\n");
606
607 return errors;
608}
609
610/*
611 This function performs an integrity check of the database
612*/
613PAKFIRE_EXPORT int pakfire_db_check(struct pakfire_db* db) {
614 int r;
615
616 // Perform integrity check
617 r = pakfire_db_integrity_check(db);
618 if (r)
619 return 1;
620
621 // Perform foreign key check
622 r = pakfire_db_foreign_key_check(db);
623 if (r)
624 return 1;
625
626 return 0;
627}
628
1fb2b526
MT
629static int pakfire_db_add_dependencies(struct pakfire_db* db, unsigned long id, PakfirePackage pkg) {
630 sqlite3_stmt* stmt = NULL;
631 int r = 1;
632
633 const char* sql = "INSERT INTO dependencies(pkg, type, dependency) VALUES(?, ?, ?)";
634
635 // Prepare the statement
636 r = sqlite3_prepare_v2(db->handle, sql, -1, &stmt, NULL);
637 if (r) {
638 ERROR(db->pakfire, "Could not prepare SQL statement: %s: %s\n",
639 sql, sqlite3_errmsg(db->handle));
640 goto END;
641 }
642
643 const struct __relation {
644 const char* type;
645 PakfireRelationList (*func)(PakfirePackage);
646 } relations[] = {
647 { "provides", pakfire_package_get_provides },
648 { "prerequires", pakfire_package_get_prerequires },
649 { "requires", pakfire_package_get_requires },
650 { "conflicts", pakfire_package_get_conflicts },
651 { "obsoletes", pakfire_package_get_obsoletes },
652 { "recommends", pakfire_package_get_recommends },
653 { "suggests", pakfire_package_get_suggests },
654 { NULL, NULL },
655 };
656
657 for (const struct __relation* relation = relations; relation->type; relation++) {
658 PakfireRelationList list = relation->func(pkg);
659 if (!list)
660 continue;
661
b76d7b47
MT
662 for (unsigned int i = 0; i < pakfire_relationlist_size(list); i++) {
663 PakfireRelation rel = pakfire_relationlist_get(list, i);
1fb2b526
MT
664 if (!rel)
665 goto END;
666
667 char* dependency = pakfire_relation_str(rel);
668 if (!dependency) {
669 pakfire_relation_unref(rel);
670 r = 1;
671 goto END;
672 }
673
674 // Bind package ID
675 r = sqlite3_bind_int64(stmt, 1, id);
676 if (r) {
677 ERROR(db->pakfire, "Could not bind id: %s\n",
678 sqlite3_errmsg(db->handle));
679 pakfire_relation_unref(rel);
680 goto END;
681 }
682
683 // Bind type
684 r = sqlite3_bind_text(stmt, 2, relation->type, -1, NULL);
685 if (r) {
686 ERROR(db->pakfire, "Could not bind type: %s\n",
687 sqlite3_errmsg(db->handle));
688 pakfire_relation_unref(rel);
689 goto END;
690 }
691
692 // Bind dependency
693 r = sqlite3_bind_text(stmt, 3, dependency, -1, NULL);
694 if (r) {
695 ERROR(db->pakfire, "Could not bind dependency: %s\n",
696 sqlite3_errmsg(db->handle));
697 pakfire_relation_unref(rel);
698 goto END;
699 }
700
701 // Execute query
702 do {
703 r = sqlite3_step(stmt);
704 } while (r == SQLITE_BUSY);
705
706 pakfire_relation_unref(rel);
707 free(dependency);
708
709 // Reset bound values
710 sqlite3_reset(stmt);
711 }
712
713 pakfire_relationlist_unref(list);
714 }
715
716 // All okay
717 r = 0;
718
719END:
720 if (stmt)
721 sqlite3_finalize(stmt);
722
723 return r;
724}
725
f5c77233
MT
726static int pakfire_db_add_files(struct pakfire_db* db, unsigned long id, PakfireArchive archive) {
727 sqlite3_stmt* stmt = NULL;
dccd04a4 728 int r = 1;
f5c77233
MT
729
730 // Get the filelist from the archive
5e9463ec
MT
731 PakfireFilelist filelist = pakfire_archive_get_filelist(archive);
732 if (!filelist) {
f5c77233
MT
733 ERROR(db->pakfire, "Could not fetch filelist from archive\n");
734 return 1;
735 }
736
5e9463ec
MT
737 // Nothing to do if the list is empty
738 if (pakfire_filelist_is_empty(filelist))
739 goto END;
740
f5c77233
MT
741 const char* sql = "INSERT INTO files(pkg, name, size, type, config, datafile, mode, "
742 "user, 'group', hash1, mtime, capabilities) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
743
744 // Prepare the statement
745 r = sqlite3_prepare_v2(db->handle, sql, -1, &stmt, NULL);
746 if (r) {
747 ERROR(db->pakfire, "Could not prepare SQL statement: %s: %s\n",
748 sql, sqlite3_errmsg(db->handle));
749 goto END;
750 }
751
5e9463ec
MT
752 for (unsigned int i = 0; i < pakfire_filelist_size(filelist); i++) {
753 PakfireFile file = pakfire_filelist_get(filelist, i);
754
f5c77233
MT
755 // Bind package ID
756 r = sqlite3_bind_int64(stmt, 1, id);
757 if (r) {
758 ERROR(db->pakfire, "Could not bind id: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 759 pakfire_file_unref(file);
f5c77233
MT
760 goto END;
761 }
762
763 // Bind name
764 const char* name = pakfire_file_get_name(file);
765
766 r = sqlite3_bind_text(stmt, 2, name, -1, NULL);
767 if (r) {
768 ERROR(db->pakfire, "Could not bind name: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 769 pakfire_file_unref(file);
f5c77233
MT
770 goto END;
771 }
772
773 // Bind size
774 size_t size = pakfire_file_get_size(file);
775
776 r = sqlite3_bind_int64(stmt, 3, size);
777 if (r) {
778 ERROR(db->pakfire, "Could not bind size: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 779 pakfire_file_unref(file);
f5c77233
MT
780 goto END;
781 }
782
783 // Bind type - XXX this is char which isn't very helpful
784 //char type = pakfire_file_get_type(file);
785
786 r = sqlite3_bind_null(stmt, 4);
787 if (r) {
788 ERROR(db->pakfire, "Could not bind type: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 789 pakfire_file_unref(file);
f5c77233
MT
790 goto END;
791 }
792
793 // Bind config - XXX TODO
794 r = sqlite3_bind_null(stmt, 5);
795 if (r) {
796 ERROR(db->pakfire, "Could not bind config: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 797 pakfire_file_unref(file);
f5c77233
MT
798 goto END;
799 }
800
801 // Bind datafile - XXX TODO
802 r = sqlite3_bind_null(stmt, 6);
803 if (r) {
804 ERROR(db->pakfire, "Could not bind datafile: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 805 pakfire_file_unref(file);
f5c77233
MT
806 goto END;
807 }
808
809 // Bind mode
810 mode_t mode = pakfire_file_get_mode(file);
811
812 r = sqlite3_bind_int64(stmt, 7, mode);
813 if (r) {
814 ERROR(db->pakfire, "Could not bind mode: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 815 pakfire_file_unref(file);
f5c77233
MT
816 goto END;
817 }
818
819 // Bind user
820 const char* user = pakfire_file_get_user(file);
821
822 r = sqlite3_bind_text(stmt, 8, user, -1, NULL);
823 if (r) {
824 ERROR(db->pakfire, "Could not bind user: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 825 pakfire_file_unref(file);
f5c77233
MT
826 goto END;
827 }
828
829 // Bind group
830 const char* group = pakfire_file_get_group(file);
831
832 r = sqlite3_bind_text(stmt, 9, group, -1, NULL);
833 if (r) {
834 ERROR(db->pakfire, "Could not bind group: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 835 pakfire_file_unref(file);
f5c77233
MT
836 goto END;
837 }
838
839 // Bind hash1
840 const char* chksum = pakfire_file_get_chksum(file);
841
842 r = sqlite3_bind_text(stmt, 10, chksum, -1, NULL);
843 if (r) {
844 ERROR(db->pakfire, "Could not bind hash1: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 845 pakfire_file_unref(file);
f5c77233
MT
846 goto END;
847 }
848
849 // Bind mtime
850 time_t mtime = pakfire_file_get_time(file);
851
852 r = sqlite3_bind_int64(stmt, 11, mtime);
853 if (r) {
854 ERROR(db->pakfire, "Could not bind mtime: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 855 pakfire_file_unref(file);
f5c77233
MT
856 goto END;
857 }
858
859 // Bind capabilities - XXX TODO
860 r = sqlite3_bind_null(stmt, 12);
861 if (r) {
862 ERROR(db->pakfire, "Could not bind capabilities: %s\n", sqlite3_errmsg(db->handle));
5e9463ec 863 pakfire_file_unref(file);
f5c77233
MT
864 goto END;
865 }
866
867 // Execute query
868 do {
869 r = sqlite3_step(stmt);
870 } while (r == SQLITE_BUSY);
871
872 // Move on to next file
5e9463ec 873 pakfire_file_unref(file);
f5c77233
MT
874
875 // Reset bound values
876 sqlite3_reset(stmt);
877 }
878
879 // All okay
880 r = 0;
881
882END:
883 if (stmt)
884 sqlite3_finalize(stmt);
885
5e9463ec
MT
886 pakfire_filelist_unref(filelist);
887
f5c77233
MT
888 return r;
889}
890
265f539a
MT
891static int pakfire_db_add_scriptlets(struct pakfire_db* db, unsigned long id, PakfireArchive archive) {
892 sqlite3_stmt* stmt = NULL;
893 int r = 1;
894
895 struct pakfire_scriptlet_type* scriptlet_type = PAKFIRE_SCRIPTLET_TYPES;
896 struct pakfire_scriptlet* scriptlet;
897
898 const char* sql = "INSERT INTO scriptlets(pkg, type, scriptlet) VALUES(?, ?, ?)";
899
900 // Prepare the statement
901 r = sqlite3_prepare_v2(db->handle, sql, -1, &stmt, NULL);
902 if (r) {
903 ERROR(db->pakfire, "Could not prepare SQL statement: %s: %s\n",
904 sql, sqlite3_errmsg(db->handle));
905 goto END;
906 }
907
908 while (scriptlet_type->type) {
909 // Fetch the scriptlet
910 scriptlet = pakfire_archive_get_scriptlet(archive, scriptlet_type->type);
911
912 // Go to next one if the archive does not have a scriptlet of the given type
913 if (!scriptlet) {
914 scriptlet_type++;
915 continue;
916 }
917
918 // Bind package ID
919 r = sqlite3_bind_int64(stmt, 1, id);
920 if (r) {
921 ERROR(db->pakfire, "Could not bind id: %s\n", sqlite3_errmsg(db->handle));
922 goto END;
923 }
924
925 // Bind handle
926 r = sqlite3_bind_text(stmt, 2, scriptlet_type->handle, -1, NULL);
927 if (r) {
928 ERROR(db->pakfire, "Could not bind type: %s\n", sqlite3_errmsg(db->handle));
929 goto END;
930 }
931
932 // Bind scriptlet
933 r = sqlite3_bind_text(stmt, 3, scriptlet->data, scriptlet->size, NULL);
934 if (r) {
935 ERROR(db->pakfire, "Could not bind scriptlet: %s\n", sqlite3_errmsg(db->handle));
936 goto END;
937 }
938
939 // Execute query
940 do {
941 r = sqlite3_step(stmt);
942 } while (r == SQLITE_BUSY);
943
944 // Reset bound values
945 sqlite3_reset(stmt);
946
947 scriptlet_type++;
948 }
949
950 // All okay
951 r = 0;
952
953END:
954 if (stmt)
955 sqlite3_finalize(stmt);
956
957 return r;
958}
959
f5c77233
MT
960PAKFIRE_EXPORT int pakfire_db_add_package(struct pakfire_db* db,
961 PakfirePackage pkg, PakfireArchive archive) {
e49b93d1
MT
962 sqlite3_stmt* stmt = NULL;
963 int r;
964
965 // Begin a new transaction
966 r = pakfire_db_begin_transaction(db);
967 if (r)
968 goto ROLLBACK;
969
970 const char* sql = "INSERT INTO packages(name, epoch, version, release, arch, groups, "
971 "filename, size, inst_size, hash1, license, summary, description, uuid, vendor, "
1ca6a13d
MT
972 "build_host, build_time, installed, repository, reason) VALUES(?, ?, "
973 "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, ?, ?)";
e49b93d1
MT
974
975 // Prepare the statement
976 r = sqlite3_prepare_v2(db->handle, sql, strlen(sql), &stmt, NULL);
977 if (r != SQLITE_OK) {
978 ERROR(db->pakfire, "Could not prepare SQL statement: %s: %s\n",
979 sql, sqlite3_errmsg(db->handle));
980 goto ROLLBACK;
981 }
982
983 // Bind name
984 const char* name = pakfire_package_get_name(pkg);
985
986 r = sqlite3_bind_text(stmt, 1, name, -1, NULL);
987 if (r) {
988 ERROR(db->pakfire, "Could not bind name: %s\n", sqlite3_errmsg(db->handle));
989 goto ROLLBACK;
990 }
991
992 // Bind epoch
993 unsigned long epoch = pakfire_package_get_epoch(pkg);
994
995 r = sqlite3_bind_int64(stmt, 2, epoch);
996 if (r) {
997 ERROR(db->pakfire, "Could not bind epoch: %s\n", sqlite3_errmsg(db->handle));
998 goto ROLLBACK;
999 }
1000
1001 // Bind version
1002 const char* version = pakfire_package_get_version(pkg);
1003
1004 r = sqlite3_bind_text(stmt, 3, version, -1, NULL);
1005 if (r) {
1006 ERROR(db->pakfire, "Could not bind version: %s\n", sqlite3_errmsg(db->handle));
1007 goto ROLLBACK;
1008 }
1009
1010 // Bind release
1011 const char* release = pakfire_package_get_release(pkg);
1012
1013 r = sqlite3_bind_text(stmt, 4, release, -1, NULL);
1014 if (r) {
1015 ERROR(db->pakfire, "Could not bind release: %s\n", sqlite3_errmsg(db->handle));
1016 goto ROLLBACK;
1017 }
1018
1019 // Bind arch
1020 const char* arch = pakfire_package_get_arch(pkg);
1021
1022 r = sqlite3_bind_text(stmt, 5, arch, -1, NULL);
1023 if (r) {
1024 ERROR(db->pakfire, "Could not bind arch: %s\n", sqlite3_errmsg(db->handle));
1025 goto ROLLBACK;
1026 }
1027
1028 // Bind groups
1029 const char* groups = pakfire_package_get_groups(pkg);
1030
1031 r = sqlite3_bind_text(stmt, 6, groups, -1, NULL);
1032 if (r) {
1033 ERROR(db->pakfire, "Could not bind groups: %s\n", sqlite3_errmsg(db->handle));
1034 goto ROLLBACK;
1035 }
1036
1037 // Bind filename
1038 const char* filename = pakfire_package_get_filename(pkg);
1039
1040 r = sqlite3_bind_text(stmt, 7, filename, -1, NULL);
1041 if (r) {
1042 ERROR(db->pakfire, "Could not bind filename: %s\n", sqlite3_errmsg(db->handle));
1043 goto ROLLBACK;
1044 }
1045
1046 // Bind size
1047 unsigned long long size = pakfire_package_get_downloadsize(pkg);
1048
1049 r = sqlite3_bind_int64(stmt, 8, size);
1050 if (r) {
1051 ERROR(db->pakfire, "Could not bind size: %s\n", sqlite3_errmsg(db->handle));
1052 goto ROLLBACK;
1053 }
1054
1055 // Bind installed size
1056 unsigned long long inst_size = pakfire_package_get_installsize(pkg);
1057
1058 r = sqlite3_bind_int64(stmt, 9, inst_size);
1059 if (r) {
1060 ERROR(db->pakfire, "Could not bind inst_size: %s\n", sqlite3_errmsg(db->handle));
1061 goto ROLLBACK;
1062 }
1063
1064 // Bind hash1
1065 const char* hash1 = pakfire_package_get_checksum(pkg);
1066
1067 r = sqlite3_bind_text(stmt, 10, hash1, -1, NULL);
1068 if (r) {
1069 ERROR(db->pakfire, "Could not bind hash1: %s\n", sqlite3_errmsg(db->handle));
1070 goto ROLLBACK;
1071 }
1072
1073 // Bind license
1074 const char* license = pakfire_package_get_license(pkg);
1075
1076 r = sqlite3_bind_text(stmt, 11, license, -1, NULL);
1077 if (r) {
1078 ERROR(db->pakfire, "Could not bind license: %s\n", sqlite3_errmsg(db->handle));
1079 goto ROLLBACK;
1080 }
1081
1082 // Bind summary
1083 const char* summary = pakfire_package_get_summary(pkg);
1084
1085 r = sqlite3_bind_text(stmt, 12, summary, -1, NULL);
1086 if (r) {
1087 ERROR(db->pakfire, "Could not bind summary: %s\n", sqlite3_errmsg(db->handle));
1088 goto ROLLBACK;
1089 }
1090
1091 // Bind description
1092 const char* description = pakfire_package_get_description(pkg);
1093
1094 r = sqlite3_bind_text(stmt, 13, description, -1, NULL);
1095 if (r) {
1096 ERROR(db->pakfire, "Could not bind description: %s\n", sqlite3_errmsg(db->handle));
1097 goto ROLLBACK;
1098 }
1099
1100 // Bind uuid
1101 const char* uuid = pakfire_package_get_uuid(pkg);
1102
1103 r = sqlite3_bind_text(stmt, 14, uuid, -1, NULL);
1104 if (r) {
1105 ERROR(db->pakfire, "Could not bind uuid: %s\n", sqlite3_errmsg(db->handle));
1106 goto ROLLBACK;
1107 }
1108
1109 // Bind vendor
1110 const char* vendor = pakfire_package_get_vendor(pkg);
1111
1112 r = sqlite3_bind_text(stmt, 14, vendor, -1, NULL);
1113 if (r) {
1114 ERROR(db->pakfire, "Could not bind vendor: %s\n", sqlite3_errmsg(db->handle));
1115 goto ROLLBACK;
1116 }
1117
e49b93d1
MT
1118 // Bind build_host
1119 const char* buildhost = pakfire_package_get_buildhost(pkg);
1120
1121 r = sqlite3_bind_text(stmt, 16, buildhost, -1, NULL);
1122 if (r) {
1123 ERROR(db->pakfire, "Could not bind build_host: %s\n", sqlite3_errmsg(db->handle));
1124 goto ROLLBACK;
1125 }
1126
1127 // Bind build_time
1128 unsigned long long build_time = pakfire_package_get_buildtime(pkg);
1129
1130 r = sqlite3_bind_int64(stmt, 17, build_time);
1131 if (r) {
1132 ERROR(db->pakfire, "Could not bind build_time: %s\n", sqlite3_errmsg(db->handle));
1133 goto ROLLBACK;
1134 }
1135
1136 // Bind repository name
1137 PakfireRepo repo = pakfire_package_get_repo(pkg);
1138 if (repo) {
1139 const char* repo_name = pakfire_repo_get_name(repo);
1140 pakfire_repo_unref(repo);
1141
1142 r = sqlite3_bind_text(stmt, 18, repo_name, -1, NULL);
1143 if (r)
1144 goto ROLLBACK;
1145
1146 // No repository?
1147 } else {
1148 r = sqlite3_bind_null(stmt, 18);
1149 if (r)
1150 goto ROLLBACK;
1151 }
1152
1153 // XXX TODO Bind reason
1154 r = sqlite3_bind_null(stmt, 19);
1155 if (r)
1156 goto ROLLBACK;
1157
1158 // Run query
1159 do {
1160 r = sqlite3_step(stmt);
1161 } while (r == SQLITE_BUSY);
1162
1163 if (r != SQLITE_DONE) {
1164 ERROR(db->pakfire, "Could not add package to database: %s\n",
1165 sqlite3_errmsg(db->handle));
1166 goto ROLLBACK;
1167 }
1168
f5c77233
MT
1169 // Save package ID
1170 unsigned long packages_id = sqlite3_last_insert_rowid(db->handle);
1171
e49b93d1 1172 // This is done
f5c77233
MT
1173 r = sqlite3_finalize(stmt);
1174 if (r == SQLITE_OK)
1175 stmt = NULL;
1176
1fb2b526
MT
1177 // Add dependencies
1178 r = pakfire_db_add_dependencies(db, packages_id, pkg);
1179 if (r)
1180 goto ROLLBACK;
1181
f5c77233
MT
1182 // Add files
1183 r = pakfire_db_add_files(db, packages_id, archive);
1184 if (r)
1185 goto ROLLBACK;
e49b93d1 1186
265f539a
MT
1187 // Add scriptlets
1188 r = pakfire_db_add_scriptlets(db, packages_id, archive);
1189 if (r)
1190 goto ROLLBACK;
1191
e49b93d1
MT
1192 // All done, commit!
1193 r = pakfire_db_commit(db);
1194 if (r)
1195 goto ROLLBACK;
1196
1197 return 0;
1198
1199ROLLBACK:
f5c77233
MT
1200 if (stmt)
1201 sqlite3_finalize(stmt);
e49b93d1
MT
1202
1203 pakfire_db_rollback(db);
1204
1205 return 1;
eafbe2ce
MT
1206}
1207
18bf891d 1208PAKFIRE_EXPORT int pakfire_db_remove_package(struct pakfire_db* db, PakfirePackage pkg) {
eafbe2ce
MT
1209 return 0; // TODO
1210}