From aa283cd60c5acf4610c8a24e4ed94c6ba61609f3 Mon Sep 17 00:00:00 2001 From: Silvan Calarco Date: Sat, 6 Jul 2024 15:08:52 +0200 Subject: [PATCH] backend-sqlite3,DistroqueryAPI: improve requirements management in sqlite db and distroquery API --- src/DistroqueryAPI.cpp | 37 +++++++++++--- src/backend-sqlite3.c | 14 ++--- src/distroquery.cpp | 45 +--------------- src/distroquery_functions.cpp | 74 +++++++++++++++++++++++++++ src/include/distroquery_functions.hpp | 4 ++ 5 files changed, 117 insertions(+), 57 deletions(-) diff --git a/src/DistroqueryAPI.cpp b/src/DistroqueryAPI.cpp index d0514ec..dc82225 100644 --- a/src/DistroqueryAPI.cpp +++ b/src/DistroqueryAPI.cpp @@ -95,7 +95,8 @@ json DistroqueryAPI::getPackageSourceDetailsById(configTag* ct, long id) { j["download_url"] = string(ct->download_prefix) + ct->download_dir + "/SRPMS.base/" + string(j["name"]) + "-" + string(j["version"]) + "-" + string(j["release"]) + ".src.rpm"; // Source URL - j["source_url"] = "https://src.openmamba.org/rpms/" + string(j["name"]); + string name = string(j["name"]); + j["source_url"] = "https://src.openmamba.org/rpms/" + replaceAll(name, "+", "Plus"); } else { j["error"] = "no results from query '" + sql + "'"; return j; @@ -239,6 +240,7 @@ json DistroqueryAPI::getPackageDetails(string repository, string package, string j["error"] = "error opening database for repository " + repository + " and arch " + arch; return j; } + attachCtDatabases(ct, db, arch); sql = "SELECT * FROM packages WHERE name = '" + package + "'"; if (sqlite3_prepare_v2(db, sql.c_str(), sql.length(), &stmt, NULL) == SQLITE_OK) { @@ -313,14 +315,14 @@ json DistroqueryAPI::getPackageDetails(string repository, string package, string } // Requires - sql = "SELECT * FROM requires,provided WHERE requires.id_package=" + to_string(id) + - " AND provided.id=requires.id_provided ORDER BY provided.name"; + sql = "SELECT * FROM requires WHERE requires.id_package=" + to_string(id); +// " AND provided.id=requires.id_provided ORDER BY provided.name"; j["requires"] = json::array(); if (sqlite3_prepare_v2(db, sql.c_str(), sql.length(), &stmt2, NULL) == SQLITE_OK) { while (sqlite3_step(stmt2) == SQLITE_ROW) { json require = {}; long id_provided = sqlite3_column_int(stmt2,sqlite3_find_column_id(stmt2, NULL, "id_provided")); - require["name"] = reinterpret_cast(sqlite3_column_text(stmt2,sqlite3_find_column_id(stmt2, NULL, "name"))); + require["name"] = reinterpret_cast(sqlite3_column_text(stmt2,sqlite3_find_column_id(stmt2, NULL, "requirename"))); require["flags"] = rpmSenseFlagsToString(sqlite3_column_int(stmt2,sqlite3_find_column_id(stmt2, NULL, "requireflags"))); require["version"] = reinterpret_cast(sqlite3_column_text(stmt2,sqlite3_find_column_id(stmt2, NULL, "requireversion"))); require["providers"] = json::array(); @@ -330,11 +332,31 @@ json DistroqueryAPI::getPackageDetails(string repository, string package, string while (sqlite3_step(stmt3) == SQLITE_ROW) { json provider = {}; provider["name"] = reinterpret_cast(sqlite3_column_text(stmt3,sqlite3_find_column_id(stmt3, NULL, "name"))); - provider["altrepository"] = sqlite3_column_int(stmt3,sqlite3_find_column_id(stmt3, NULL, "altrepostory")); + provider["repository"] = ct->tag; require["providers"].push_back(provider); } sqlite3_finalize(stmt3); } + // Resolve requires provided in upstream (alternative) repositories + int i = 0; + while (ct->repository[i]) { + if (ct->repository[i] != ct) { + string altprefix = string(ct->repository[i]->tag) + "_" + arch + "."; + sql = "SELECT * FROM " + altprefix + "provides," + altprefix + + "packages WHERE providename='" + string(require["name"]) + + "' AND " + altprefix + "packages.id=id_package"; + if (sqlite3_prepare_v2(db, sql.c_str(), sql.length(), &stmt3, NULL) == SQLITE_OK) { + while (sqlite3_step(stmt3) == SQLITE_ROW) { + json provider = {}; + provider["name"] = reinterpret_cast(sqlite3_column_text(stmt3,sqlite3_find_column_id(stmt3, NULL, "name"))); + provider["repository"] = ct->repository[i]->tag; + require["providers"].push_back(provider); + } + sqlite3_finalize(stmt3); + } + } + i++; + } j["requires"].push_back(require); } sqlite3_finalize(stmt2); @@ -380,10 +402,11 @@ void DistroqueryAPI::getApiResponse(string path_info) { if (path_split.size() < 3 || path_split.size() > 4) sendErrorResponse("expected 3 or 4 arguments for " + path_split[0]); json details; + string package = urlDecode(path_split[2]); if (path_split.size() == 3) { - details = getPackageSourceDetails(path_split[1], path_split[2]); + details = getPackageSourceDetails(path_split[1], package); } else { - details = getPackageDetails(path_split[1], path_split[2], path_split[3]); + details = getPackageDetails(path_split[1], package, path_split[3]); } cout << details.dump(); } else { diff --git a/src/backend-sqlite3.c b/src/backend-sqlite3.c index ed616c6..1906639 100644 --- a/src/backend-sqlite3.c +++ b/src/backend-sqlite3.c @@ -323,10 +323,10 @@ long generateSQLite_add_changelog(sqlite3 *db, struct changeLog* firstchangelog, "id_package INTEGER, obsoletename STRING, obsoleteflags INTEGER, obsoleteversion STRING" #define SQLITE_TABLE_provides "id INTEGER PRIMARY KEY, "\ - "id_package INTEGER, id_provided INTEGER, provideflags INTEGER, provideversion STRING" + "id_package INTEGER, id_provided INTEGER, providename STRING, provideflags INTEGER, provideversion STRING" #define SQLITE_TABLE_requires "id INTEGER PRIMARY KEY, "\ - "id_package INTEGER, id_provided STRING, requireflags INTEGER, requireversion STRING" + "id_package INTEGER, id_provided STRING, requirename STRING, requireflags INTEGER, requireversion STRING" int generateSQLite_packages(struct configTag *ct, sqlite3 *db, int arch) { @@ -388,7 +388,7 @@ generateSQLite_packages(struct configTag *ct, sqlite3 *db, int arch) { /* provides */ for (i = 0; i < currpackage->providecount; i++) { - snprintf(sqlite3_query, PATH_MAX, "INSERT INTO provides VALUES(NULL,%ld,%ld,%d,?);", + snprintf(sqlite3_query, PATH_MAX, "INSERT INTO provides VALUES(NULL,%ld,%ld,?,%d,?);", currpackage->id, currpackage->provided[i]->id, currpackage->provideflags[i]); @@ -396,7 +396,8 @@ generateSQLite_packages(struct configTag *ct, sqlite3 *db, int arch) { if (sqlite3_prepare_v2(db, sqlite3_query, -1, &stmt, NULL)) { fprintf(stderr, "ERROR: SQLite: (%s) %s\n", sqlite3_query, sqlite3_errmsg(db)); } - sqlite3_bind_text(stmt, 1, currpackage->provideversion[i], -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 1, currpackage->providename[i], -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 2, currpackage->provideversion[i], -1, SQLITE_STATIC); if (sqlite3_step(stmt) != SQLITE_DONE) { fprintf(stderr, "ERROR: SQLite: (%s) %s\n", sqlite3_query, sqlite3_errmsg(db)); return 3; @@ -407,7 +408,7 @@ generateSQLite_packages(struct configTag *ct, sqlite3 *db, int arch) { /* requires */ for (i = 0; i < currpackage->requirecount; i++) { if (currpackage->require[i]->resolved) { - snprintf(sqlite3_query, PATH_MAX, "INSERT INTO requires VALUES(NULL,%ld,%ld,%ld,?);", + snprintf(sqlite3_query, PATH_MAX, "INSERT INTO requires VALUES(NULL,%ld,%ld,?,%ld,?);", currpackage->id, currpackage->require[i]->resolved->id, currpackage->require[i]->flags); @@ -415,7 +416,8 @@ generateSQLite_packages(struct configTag *ct, sqlite3 *db, int arch) { if (sqlite3_prepare_v2(db, sqlite3_query, -1, &stmt, NULL)) { fprintf(stderr, "ERROR: SQLite: (%s) %s\n", sqlite3_query, sqlite3_errmsg(db)); } - sqlite3_bind_text(stmt, 1, currpackage->require[i]->version, -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 1, currpackage->require[i]->name, -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 2, currpackage->require[i]->version, -1, SQLITE_STATIC); if (sqlite3_step(stmt) != SQLITE_DONE) { fprintf(stderr, "ERROR: SQLite: (%s) %s\n", sqlite3_query, sqlite3_errmsg(db)); return 3; diff --git a/src/distroquery.cpp b/src/distroquery.cpp index 1aada88..939211a 100644 --- a/src/distroquery.cpp +++ b/src/distroquery.cpp @@ -178,49 +178,6 @@ char* resolveFilePath(sqlite3 *db, long id, char *buffer) { return buffer; } -void attachCtDatabases(struct configTag* ct, sqlite3 *db, char* arch) { - string dbname; - string sql; - int i=0; - char *errmsg; - - while (ct->repository[i]) { - if (arch) { - dbname = string(ct->repository[i]->repository_dir) + ct->repository[i]->tag + "-" + arch + ".db"; - sql = "ATTACH DATABASE '" + dbname + "' as '" + ct->repository[i]->tag + "_" + arch + "'"; - if (sqlite3_exec(db, sql.c_str(), NULL, NULL, &errmsg)) { - cerr << "ERROR: unable to exec statement for " << sql << ": " << errmsg << endl; - } - } else { - dbname = string(ct->repository[i]->repository_dir) + ct->repository[i]->tag + "-sources.db"; - sql = "ATTACH DATABASE '" + dbname + "' as '" + ct->repository[i]->tag + "_sources'"; - if (sqlite3_exec(db, sql.c_str(), NULL, NULL, &errmsg)) { - cerr << "ERROR: unable to exec statement for " << sql << ": " << errmsg << endl; - } - } - i++; - } -} - -void attachRepositoryDatabases(struct configTag* ct, sqlite3 *db, char* arch, int source) { - string dbname; - string sql; - char *errmsg; - - dbname = string(ct->repository_dir) + ct->tag + "-" + arch + ".db"; - sql = "ATTACH DATABASE '" + dbname + "' as '" + ct->tag + "_" + arch; - if (sqlite3_exec(db, sql.c_str(), NULL, NULL, &errmsg)) { - cerr << "ERROR: unable to exec statement for " << sql << ": " << errmsg << endl; - } - if (source) { - dbname = string(ct->repository_dir) + ct->tag + "-sources.db"; - sql = "ATTACH DATABASE '" + dbname + "' as '" + ct->tag + "_sources'"; - if (sqlite3_exec(db, sql.c_str(), NULL, NULL, &errmsg)) { - cerr << "ERROR: unable to exec statement for " << sql << ":: " << errmsg << endl; - } - } -} - void detachRepositoryDatabases(struct configTag* ct, sqlite3 *db, char* arch, int source) { char sql[PATH_MAX]; char *errmsg; @@ -838,7 +795,7 @@ void printSpecialQueryResponse() { if (!ct) return; db = openRepositoryDatabase(ct); if (!db) return; - attachCtDatabases(ct, db, NULL); + attachCtDatabases(ct, db); if (ct->arch[0]) { dbb = openRepositoryDatabase(ct); diff --git a/src/distroquery_functions.cpp b/src/distroquery_functions.cpp index f11ff07..c102360 100644 --- a/src/distroquery_functions.cpp +++ b/src/distroquery_functions.cpp @@ -67,6 +67,49 @@ sqlite3* openRepositoryDatabase(struct configTag* ct, string arch, string append return db; } +void attachCtDatabases(struct configTag* ct, sqlite3 *db, string arch) { + string dbname; + string sql; + int i=0; + char *errmsg; + + while (ct->repository[i]) { + if (arch != "" && arch != "sources") { + dbname = string(ct->repository[i]->repository_dir) + ct->repository[i]->tag + "-" + arch + ".db"; + sql = "ATTACH DATABASE '" + dbname + "' as '" + ct->repository[i]->tag + "_" + arch + "'"; + if (sqlite3_exec(db, sql.c_str(), NULL, NULL, &errmsg)) { + cerr << "ERROR: unable to exec statement for " << sql << ": " << errmsg << endl; + } + } else { + dbname = string(ct->repository[i]->repository_dir) + ct->repository[i]->tag + "-sources.db"; + sql = "ATTACH DATABASE '" + dbname + "' as '" + ct->repository[i]->tag + "_sources'"; + if (sqlite3_exec(db, sql.c_str(), NULL, NULL, &errmsg)) { + cerr << "ERROR: unable to exec statement for " << sql << ": " << errmsg << endl; + } + } + i++; + } +} + +void attachRepositoryDatabases(struct configTag* ct, sqlite3 *db, string arch, int source) { + string dbname; + string sql; + char *errmsg; + + dbname = string(ct->repository_dir) + ct->tag + "-" + arch + ".db"; + sql = "ATTACH DATABASE '" + dbname + "' as '" + ct->tag + "_" + arch; + if (sqlite3_exec(db, sql.c_str(), NULL, NULL, &errmsg)) { + cerr << "ERROR: unable to exec statement for " << sql << ": " << errmsg << endl; + } + if (source) { + dbname = string(ct->repository_dir) + ct->tag + "-sources.db"; + sql = "ATTACH DATABASE '" + dbname + "' as '" + ct->tag + "_sources'"; + if (sqlite3_exec(db, sql.c_str(), NULL, NULL, &errmsg)) { + cerr << "ERROR: unable to exec statement for " << sql << ":: " << errmsg << endl; + } + } +} + int sqlite3_find_column_id(sqlite3_stmt *stmt, const char* table, const char* name) { const char* colname; int id = 0; @@ -83,3 +126,34 @@ int sqlite3_find_column_id(sqlite3_stmt *stmt, const char* table, const char* na } return -1; } + +string urlDecode(string str) { + string ret; + char ch; + int i, len = str.length(); + unsigned int ii; + + for (i=0; i < len; i++){ + if (str[i] != '%') { + if (str[i] == '+') + ret += ' '; + else + ret += str[i]; + } else { + sscanf(str.substr(i + 1, 2).c_str(), "%x", &ii); + ch = static_cast(ii); + ret += ch; + i = i + 2; + } + } + return ret; +} + +string replaceAll(string str, const string& from, const string& to) { + size_t start_pos = 0; + while((start_pos = str.find(from, start_pos)) != string::npos) { + str.replace(start_pos, from.length(), to); + start_pos += to.length(); // Handles case where 'to' is a substring of 'from' + } + return str; +} diff --git a/src/include/distroquery_functions.hpp b/src/include/distroquery_functions.hpp index 8761ea8..8294ff5 100644 --- a/src/include/distroquery_functions.hpp +++ b/src/include/distroquery_functions.hpp @@ -29,7 +29,11 @@ using namespace std; string rpmSenseFlagsToString(int flags); vector split(string str, string token); sqlite3* openRepositoryDatabase(struct configTag* ct, string arch = "", string append = ""); +void attachCtDatabases(struct configTag* ct, sqlite3 *db, string arch = ""); +void attachRepositoryDatabases(struct configTag* ct, sqlite3 *db, string arch, int source); int sqlite3_find_column_id(sqlite3_stmt *stmt, const char* table, const char* name); +string urlDecode(string str); +string replaceAll(string str, const string& from, const string& to); #define HDSIZE 16 #define SSSIZE 24