📄 db.c
字号:
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- *//* This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License, * version 2, as published by the Free Software Foundation * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307, USA. */#include <string.h>#include <unistd.h>#include "db.h"GQuarkyum_db_error_quark (void){ static GQuark quark; if (!quark) quark = g_quark_from_static_string ("yum_db_error"); return quark;}#define ENCODED_PACKAGE_FILE_FILES 2048#define ENCODED_PACKAGE_FILE_TYPES 60typedef struct { GString *files; GString *types;} EncodedPackageFile;static EncodedPackageFile *encoded_package_file_new (void){ EncodedPackageFile *enc; enc = g_new0 (EncodedPackageFile, 1); enc->files = g_string_sized_new (ENCODED_PACKAGE_FILE_FILES); enc->types = g_string_sized_new (ENCODED_PACKAGE_FILE_TYPES); return enc;}static voidencoded_package_file_free (EncodedPackageFile *file){ g_string_free (file->files, TRUE); g_string_free (file->types, TRUE); g_free (file);}static GHashTable *package_files_to_hash (GSList *files){ GHashTable *hash; GSList *iter; PackageFile *file; EncodedPackageFile *enc; char *dir; char *name; hash = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) encoded_package_file_free); for (iter = files; iter; iter = iter->next) { file = (PackageFile *) iter->data; dir = g_path_get_dirname (file->name); name = g_path_get_basename (file->name); enc = (EncodedPackageFile *) g_hash_table_lookup (hash, dir); if (!enc) { enc = encoded_package_file_new (); g_hash_table_insert (hash, dir, enc); } else g_free (dir); if (enc->files->len) g_string_append_c (enc->files, '/'); g_string_append (enc->files, name); g_free (name); if (!strcmp (file->type, "dir")) g_string_append_c (enc->types, 'd'); else if (!strcmp (file->type, "file")) g_string_append_c (enc->types, 'f'); else if (!strcmp (file->type, "ghost")) g_string_append_c (enc->types, 'g'); } return hash;}char *yum_db_filename (const char *prefix){ char *filename; filename = g_strconcat (prefix, ".sqlite", NULL); return filename;}typedef enum { DB_STATUS_OK, DB_STATUS_VERSION_MISMATCH, DB_STATUS_CHECKSUM_MISMATCH, DB_STATUS_ERROR} DBStatus;static DBStatusdbinfo_status (sqlite3 *db, const char *checksum){ const char *query; int rc; sqlite3_stmt *handle = NULL; DBStatus status = DB_STATUS_ERROR; query = "SELECT dbversion, checksum FROM db_info"; rc = sqlite3_prepare (db, query, -1, &handle, NULL); if (rc != SQLITE_OK) goto cleanup; while ((rc = sqlite3_step (handle)) == SQLITE_ROW) { int dbversion; const char *dbchecksum; dbversion = sqlite3_column_int (handle, 0); dbchecksum = (const char *) sqlite3_column_text (handle, 1); if (dbversion != YUM_SQLITE_CACHE_DBVERSION) { g_message ("Warning: cache file is version %d, we need %d, will regenerate", dbversion, YUM_SQLITE_CACHE_DBVERSION); status = DB_STATUS_VERSION_MISMATCH; } else if (strcmp (checksum, dbchecksum)) { g_message ("sqlite cache needs updating, reading in metadata"); status = DB_STATUS_CHECKSUM_MISMATCH; } else status = DB_STATUS_OK; break; } cleanup: if (handle) sqlite3_finalize (handle); return status;}static voidyum_db_create_dbinfo_table (sqlite3 *db, GError **err){ int rc; const char *sql; sql = "CREATE TABLE db_info (dbversion INTEGER, checksum TEXT)"; rc = sqlite3_exec (db, sql, NULL, NULL, NULL); if (rc != SQLITE_OK) { g_set_error (err, YUM_DB_ERROR, YUM_DB_ERROR, "Can not create db_info table: %s", sqlite3_errmsg (db)); }}sqlite3 *yum_db_open (const char *path, const char *checksum, CreateTablesFn create_tables, GError **err){ int rc; sqlite3 *db = NULL; gboolean db_existed; db_existed = g_file_test (path, G_FILE_TEST_EXISTS); rc = sqlite3_open (path, &db); if (rc == SQLITE_OK) { if (db_existed) { DBStatus status = dbinfo_status (db, checksum); switch (status) { case DB_STATUS_OK: /* Everything is up-to-date */ sqlite3_close (db); return NULL; break; case DB_STATUS_CHECKSUM_MISMATCH: sqlite3_exec (db, "PRAGMA synchronous = 0", NULL, NULL, NULL); sqlite3_exec (db, "DELETE FROM db_info", NULL, NULL, NULL); return db; break; case DB_STATUS_VERSION_MISMATCH: case DB_STATUS_ERROR: sqlite3_close (db); db = NULL; unlink (path); break; } } } else { /* Let's try to delete it and try again, maybe it's a sqlite3 version mismatch. */ sqlite3_close (db); db = NULL; unlink (path); } if (!db) { rc = sqlite3_open (path, &db); if (rc != SQLITE_OK) { g_set_error (err, YUM_DB_ERROR, YUM_DB_ERROR, "Can not open SQL database: %s", sqlite3_errmsg (db)); goto cleanup; } } yum_db_create_dbinfo_table (db, err); if (*err) goto cleanup; create_tables (db, err); if (*err) goto cleanup; sqlite3_exec (db, "PRAGMA synchronous = 0", NULL, NULL, NULL); cleanup: if (*err && db) { sqlite3_close (db); db = NULL; } return db;}voidyum_db_dbinfo_update (sqlite3 *db, const char *checksum, GError **err){ int rc; char *sql; sql = g_strdup_printf ("INSERT INTO db_info (dbversion, checksum) VALUES (%d, '%s')", YUM_SQLITE_CACHE_DBVERSION, checksum); rc = sqlite3_exec (db, sql, NULL, NULL, NULL); if (rc != SQLITE_OK) g_set_error (err, YUM_DB_ERROR, YUM_DB_ERROR, "Can not update dbinfo table: %s", sqlite3_errmsg (db)); g_free (sql);}GHashTable *yum_db_read_package_ids (sqlite3 *db, GError **err){ const char *query; int rc; GHashTable *hash = NULL; sqlite3_stmt *handle = NULL; query = "SELECT pkgId, pkgKey FROM packages"; rc = sqlite3_prepare (db, query, -1, &handle, NULL); if (rc != SQLITE_OK) { g_set_error (err, YUM_DB_ERROR, YUM_DB_ERROR, "Can not prepare SQL clause: %s", sqlite3_errmsg (db)); goto cleanup; } hash = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL); while ((rc = sqlite3_step (handle)) == SQLITE_ROW) { char *pkgId; gint pkgKey; pkgId = g_strdup ((char *) sqlite3_column_text (handle, 0)); pkgKey = sqlite3_column_int (handle, 1); g_hash_table_insert (hash, pkgId, GINT_TO_POINTER (pkgKey)); } if (rc != SQLITE_DONE) g_set_error (err, YUM_DB_ERROR, YUM_DB_ERROR, "Error reading from SQL: %s", sqlite3_errmsg (db)); cleanup: if (handle) sqlite3_finalize (handle); return hash;}voidyum_db_create_primary_tables (sqlite3 *db, GError **err){ int rc; const char *sql; sql = "CREATE TABLE packages (" " pkgKey INTEGER PRIMARY KEY," " pkgId TEXT," " name TEXT," " arch TEXT," " version TEXT," " epoch TEXT," " release TEXT," " summary TEXT," " description TEXT," " url TEXT," " time_file INTEGER," " time_build INTEGER," " rpm_license TEXT," " rpm_vendor TEXT," " rpm_group TEXT," " rpm_buildhost TEXT," " rpm_sourcerpm TEXT," " rpm_header_start INTEGER," " rpm_header_end INTEGER," " rpm_packager TEXT," " size_package INTEGER," " size_installed INTEGER," " size_archive INTEGER," " location_href TEXT," " location_base TEXT," " checksum_type TEXT)"; rc = sqlite3_exec (db, sql, NULL, NULL, NULL); if (rc != SQLITE_OK) { g_set_error (err, YUM_DB_ERROR, YUM_DB_ERROR, "Can not create packages table: %s", sqlite3_errmsg (db)); return; } sql = "CREATE INDEX packagename ON packages (name)"; rc = sqlite3_exec (db, sql, NULL, NULL, NULL); if (rc != SQLITE_OK) { g_set_error (err, YUM_DB_ERROR, YUM_DB_ERROR, "Can not create packagename index: %s", sqlite3_errmsg (db)); return; } sql = "CREATE INDEX packageId ON packages (pkgId)"; rc = sqlite3_exec (db, sql, NULL, NULL, NULL); if (rc != SQLITE_OK) { g_set_error (err, YUM_DB_ERROR, YUM_DB_ERROR, "Can not create packageId index: %s", sqlite3_errmsg (db)); return; } sql = "CREATE TABLE files (" " name TEXT," " type TEXT," " pkgKey INTEGER)"; rc = sqlite3_exec (db, sql, NULL, NULL, NULL); if (rc != SQLITE_OK) { g_set_error (err, YUM_DB_ERROR, YUM_DB_ERROR, "Can not create files table: %s", sqlite3_errmsg (db)); return; } sql = "CREATE INDEX filenames ON files (name)"; rc = sqlite3_exec (db, sql, NULL, NULL, NULL); if (rc != SQLITE_OK) { g_set_error (err, YUM_DB_ERROR, YUM_DB_ERROR, "Can not create filenames index: %s", sqlite3_errmsg (db)); return; } sql = "CREATE TABLE %s (" " name TEXT," " flags TEXT," " epoch TEXT," " version TEXT," " release TEXT," " pkgKey INTEGER %s)"; const char *deps[] = { "requires", "provides", "conflicts", "obsoletes", NULL }; int i; const char *pkgindexsql = "CREATE INDEX pkg%s on %s (pkgKey)"; const char *nameindexsql = "CREATE INDEX %sname ON %s (name)"; for (i = 0; deps[i]; i++) { const char *prereq; char *query; if (!strcmp(deps[i], "requires")) { prereq = ", pre BOOLEAN DEFAULT FALSE"; } else prereq = ""; query = g_strdup_printf (sql, deps[i], prereq); rc = sqlite3_exec (db, query, NULL, NULL, NULL); g_free (query); if (rc != SQLITE_OK) { g_set_error (err, YUM_DB_ERROR, YUM_DB_ERROR, "Can not create %s table: %s", deps[i], sqlite3_errmsg (db)); return; } query = g_strdup_printf(pkgindexsql, deps[i], deps[i]); rc = sqlite3_exec (db, query, NULL, NULL, NULL); g_free (query); if (rc != SQLITE_OK) { g_set_error (err, YUM_DB_ERROR, YUM_DB_ERROR, "Can not create index on %s table: %s", deps[i], sqlite3_errmsg (db)); return; } if (i < 2) { query = g_strdup_printf(nameindexsql, deps[i], deps[i]); rc = sqlite3_exec (db, query, NULL, NULL, NULL); if (rc != SQLITE_OK) { g_set_error (err, YUM_DB_ERROR, YUM_DB_ERROR, "Can not create %sname index: %s", deps[i], sqlite3_errmsg (db)); return; } } } sql = "CREATE TRIGGER removals AFTER DELETE ON packages" " BEGIN" " DELETE FROM files WHERE pkgKey = old.pkgKey;" " DELETE FROM requires WHERE pkgKey = old.pkgKey;" " DELETE FROM provides WHERE pkgKey = old.pkgKey;" " DELETE FROM conflicts WHERE pkgKey = old.pkgKey;" " DELETE FROM obsoletes WHERE pkgKey = old.pkgKey;" " END;"; rc = sqlite3_exec (db, sql, NULL, NULL, NULL); if (rc != SQLITE_OK) { g_set_error (err, YUM_DB_ERROR, YUM_DB_ERROR, "Can not create removals trigger: %s", sqlite3_errmsg (db)); return; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -