From: Michael Tremer Date: Sat, 23 Jan 2021 16:20:49 +0000 (+0000) Subject: libpakfire: db: Add check function to check database integrity X-Git-Tag: 0.9.28~1285^2~815 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a1571786a1a3ed969952c086410c791129e32220;p=pakfire.git libpakfire: db: Add check function to check database integrity Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/db.c b/src/libpakfire/db.c index eb70b3f77..ef2427c75 100644 --- a/src/libpakfire/db.c +++ b/src/libpakfire/db.c @@ -511,6 +511,119 @@ PAKFIRE_EXPORT struct pakfire_db* pakfire_db_unref(struct pakfire_db* db) { return NULL; } +static unsigned long pakfire_db_integrity_check(struct pakfire_db* db) { + sqlite3_stmt* stmt = NULL; + int r; + + r = sqlite3_prepare_v2(db->handle, "PRAGMA integrity_check", -1, &stmt, NULL); + if (r) { + ERROR(db->pakfire, "Could not prepare integrity check: %s\n", + sqlite3_errmsg(db->handle)); + return 1; + } + + // Count any errors + unsigned long errors = 0; + + while (1) { + do { + r = sqlite3_step(stmt); + } while (r == SQLITE_BUSY); + + if (r == SQLITE_ROW) { + const char* error = (const char*)sqlite3_column_text(stmt, 0); + + // If the message is "ok", the database has passed the check + if (strcmp(error, "ok") == 0) + continue; + + // Increment error counter + errors++; + + // Log the message + ERROR(db->pakfire, "%s\n", error); + + // Break on anything else + } else + break; + } + + sqlite3_finalize(stmt); + + if (errors) + ERROR(db->pakfire, "Database integrity check failed\n"); + else + INFO(db->pakfire, "Database integrity check passed\n"); + + return errors; +} + +static unsigned long pakfire_db_foreign_key_check(struct pakfire_db* db) { + sqlite3_stmt* stmt = NULL; + int r; + + r = sqlite3_prepare_v2(db->handle, "PRAGMA foreign_key_check", -1, &stmt, NULL); + if (r) { + ERROR(db->pakfire, "Could not prepare foreign key check: %s\n", + sqlite3_errmsg(db->handle)); + return 1; + } + + // Count any errors + unsigned long errors = 0; + + while (1) { + do { + r = sqlite3_step(stmt); + } while (r == SQLITE_BUSY); + + if (r == SQLITE_ROW) { + const unsigned char* table = sqlite3_column_text(stmt, 0); + unsigned long rowid = sqlite3_column_int64(stmt, 1); + const unsigned char* foreign_table = sqlite3_column_text(stmt, 2); + unsigned long foreign_rowid = sqlite3_column_int64(stmt, 3); + + // Increment error counter + errors++; + + // Log the message + ERROR(db->pakfire, "Foreign key violation found in %s, row %lu: " + "%lu does not exist in table %s\n", table, rowid, foreign_rowid, foreign_table); + + // Break on anything else + } else + break; + } + + sqlite3_finalize(stmt); + + if (errors) + ERROR(db->pakfire, "Foreign key check failed\n"); + else + INFO(db->pakfire, "Foreign key check passed\n"); + + return errors; +} + +/* + This function performs an integrity check of the database +*/ +PAKFIRE_EXPORT int pakfire_db_check(struct pakfire_db* db) { + int r; + + // Perform integrity check + r = pakfire_db_integrity_check(db); + if (r) + return 1; + + // Perform foreign key check + r = pakfire_db_foreign_key_check(db); + if (r) + return 1; + + return 0; +} + PAKFIRE_EXPORT int pakfire_db_add_package(struct pakfire_db* db, PakfirePackage pkg) { sqlite3_stmt* stmt = NULL; int r; diff --git a/src/libpakfire/include/pakfire/db.h b/src/libpakfire/include/pakfire/db.h index bc0f890df..daad16665 100644 --- a/src/libpakfire/include/pakfire/db.h +++ b/src/libpakfire/include/pakfire/db.h @@ -35,6 +35,8 @@ int pakfire_db_open(struct pakfire_db** db, Pakfire pakfire, int flags); struct pakfire_db* pakfire_db_ref(struct pakfire_db* db); struct pakfire_db* pakfire_db_unref(struct pakfire_db* db); +int pakfire_db_check(struct pakfire_db* db); + int pakfire_db_add_package(struct pakfire_db* db, PakfirePackage pkg); int pakfire_db_remove_package(struct pakfire_db* db, PakfirePackage pkg); diff --git a/src/libpakfire/libpakfire.sym b/src/libpakfire/libpakfire.sym index 27123d7ec..67c71f109 100644 --- a/src/libpakfire/libpakfire.sym +++ b/src/libpakfire/libpakfire.sym @@ -80,6 +80,7 @@ global: # db pakfire_db_add_package; + pakfire_db_check; pakfire_db_open; pakfire_db_ref; pakfire_db_remove_package; diff --git a/tests/libpakfire/db.c b/tests/libpakfire/db.c index e0c324e58..65b98eed1 100644 --- a/tests/libpakfire/db.c +++ b/tests/libpakfire/db.c @@ -45,9 +45,24 @@ static int test_open_rw(const struct test* t) { return 0; } +static int test_check(const struct test* t) { + struct pakfire_db* db; + + int r = pakfire_db_open(&db, t->pakfire, PAKFIRE_DB_READWRITE); + ASSERT(!r); + + // Perform check + ASSERT(!pakfire_db_check(db)); + + pakfire_db_unref(db); + + return 0; +} + int main(int argc, char** argv) { testsuite_add_test(test_open_ro); testsuite_add_test(test_open_rw); + testsuite_add_test(test_check); return testsuite_run(); }