backend-sqlite3,DistroqueryAPI: improve requirements management in sqlite db and distroquery API

This commit is contained in:
Silvan Calarco 2024-07-06 15:08:52 +02:00
parent 7ae467a639
commit aa283cd60c
5 changed files with 117 additions and 57 deletions

View File

@ -95,7 +95,8 @@ json DistroqueryAPI::getPackageSourceDetailsById(configTag* ct, long id) {
j["download_url"] = string(ct->download_prefix) + ct->download_dir + "/SRPMS.base/" + j["download_url"] = string(ct->download_prefix) + ct->download_dir + "/SRPMS.base/" +
string(j["name"]) + "-" + string(j["version"]) + "-" + string(j["release"]) + ".src.rpm"; string(j["name"]) + "-" + string(j["version"]) + "-" + string(j["release"]) + ".src.rpm";
// Source URL // 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 { } else {
j["error"] = "no results from query '" + sql + "'"; j["error"] = "no results from query '" + sql + "'";
return j; 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; j["error"] = "error opening database for repository " + repository + " and arch " + arch;
return j; return j;
} }
attachCtDatabases(ct, db, arch);
sql = "SELECT * FROM packages WHERE name = '" + package + "'"; sql = "SELECT * FROM packages WHERE name = '" + package + "'";
if (sqlite3_prepare_v2(db, sql.c_str(), sql.length(), &stmt, NULL) == SQLITE_OK) { 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 // Requires
sql = "SELECT * FROM requires,provided WHERE requires.id_package=" + to_string(id) + sql = "SELECT * FROM requires WHERE requires.id_package=" + to_string(id);
" AND provided.id=requires.id_provided ORDER BY provided.name"; // " AND provided.id=requires.id_provided ORDER BY provided.name";
j["requires"] = json::array(); j["requires"] = json::array();
if (sqlite3_prepare_v2(db, sql.c_str(), sql.length(), &stmt2, NULL) == SQLITE_OK) { if (sqlite3_prepare_v2(db, sql.c_str(), sql.length(), &stmt2, NULL) == SQLITE_OK) {
while (sqlite3_step(stmt2) == SQLITE_ROW) { while (sqlite3_step(stmt2) == SQLITE_ROW) {
json require = {}; json require = {};
long id_provided = sqlite3_column_int(stmt2,sqlite3_find_column_id(stmt2, NULL, "id_provided")); long id_provided = sqlite3_column_int(stmt2,sqlite3_find_column_id(stmt2, NULL, "id_provided"));
require["name"] = reinterpret_cast<const char*>(sqlite3_column_text(stmt2,sqlite3_find_column_id(stmt2, NULL, "name"))); require["name"] = reinterpret_cast<const char*>(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["flags"] = rpmSenseFlagsToString(sqlite3_column_int(stmt2,sqlite3_find_column_id(stmt2, NULL, "requireflags")));
require["version"] = reinterpret_cast<const char*>(sqlite3_column_text(stmt2,sqlite3_find_column_id(stmt2, NULL, "requireversion"))); require["version"] = reinterpret_cast<const char*>(sqlite3_column_text(stmt2,sqlite3_find_column_id(stmt2, NULL, "requireversion")));
require["providers"] = json::array(); require["providers"] = json::array();
@ -330,11 +332,31 @@ json DistroqueryAPI::getPackageDetails(string repository, string package, string
while (sqlite3_step(stmt3) == SQLITE_ROW) { while (sqlite3_step(stmt3) == SQLITE_ROW) {
json provider = {}; json provider = {};
provider["name"] = reinterpret_cast<const char*>(sqlite3_column_text(stmt3,sqlite3_find_column_id(stmt3, NULL, "name"))); provider["name"] = reinterpret_cast<const char*>(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); require["providers"].push_back(provider);
} }
sqlite3_finalize(stmt3); 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<const char*>(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); j["requires"].push_back(require);
} }
sqlite3_finalize(stmt2); sqlite3_finalize(stmt2);
@ -380,10 +402,11 @@ void DistroqueryAPI::getApiResponse(string path_info) {
if (path_split.size() < 3 || path_split.size() > 4) if (path_split.size() < 3 || path_split.size() > 4)
sendErrorResponse("expected 3 or 4 arguments for " + path_split[0]); sendErrorResponse("expected 3 or 4 arguments for " + path_split[0]);
json details; json details;
string package = urlDecode(path_split[2]);
if (path_split.size() == 3) { if (path_split.size() == 3) {
details = getPackageSourceDetails(path_split[1], path_split[2]); details = getPackageSourceDetails(path_split[1], package);
} else { } else {
details = getPackageDetails(path_split[1], path_split[2], path_split[3]); details = getPackageDetails(path_split[1], package, path_split[3]);
} }
cout << details.dump(); cout << details.dump();
} else { } else {

View File

@ -323,10 +323,10 @@ long generateSQLite_add_changelog(sqlite3 *db, struct changeLog* firstchangelog,
"id_package INTEGER, obsoletename STRING, obsoleteflags INTEGER, obsoleteversion STRING" "id_package INTEGER, obsoletename STRING, obsoleteflags INTEGER, obsoleteversion STRING"
#define SQLITE_TABLE_provides "id INTEGER PRIMARY KEY, "\ #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, "\ #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 int
generateSQLite_packages(struct configTag *ct, sqlite3 *db, int arch) { generateSQLite_packages(struct configTag *ct, sqlite3 *db, int arch) {
@ -388,7 +388,7 @@ generateSQLite_packages(struct configTag *ct, sqlite3 *db, int arch) {
/* provides */ /* provides */
for (i = 0; i < currpackage->providecount; i++) { 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->id,
currpackage->provided[i]->id, currpackage->provided[i]->id,
currpackage->provideflags[i]); 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)) { if (sqlite3_prepare_v2(db, sqlite3_query, -1, &stmt, NULL)) {
fprintf(stderr, "ERROR: SQLite: (%s) %s\n", sqlite3_query, sqlite3_errmsg(db)); 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) { if (sqlite3_step(stmt) != SQLITE_DONE) {
fprintf(stderr, "ERROR: SQLite: (%s) %s\n", sqlite3_query, sqlite3_errmsg(db)); fprintf(stderr, "ERROR: SQLite: (%s) %s\n", sqlite3_query, sqlite3_errmsg(db));
return 3; return 3;
@ -407,7 +408,7 @@ generateSQLite_packages(struct configTag *ct, sqlite3 *db, int arch) {
/* requires */ /* requires */
for (i = 0; i < currpackage->requirecount; i++) { for (i = 0; i < currpackage->requirecount; i++) {
if (currpackage->require[i]->resolved) { 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->id,
currpackage->require[i]->resolved->id, currpackage->require[i]->resolved->id,
currpackage->require[i]->flags); 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)) { if (sqlite3_prepare_v2(db, sqlite3_query, -1, &stmt, NULL)) {
fprintf(stderr, "ERROR: SQLite: (%s) %s\n", sqlite3_query, sqlite3_errmsg(db)); 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) { if (sqlite3_step(stmt) != SQLITE_DONE) {
fprintf(stderr, "ERROR: SQLite: (%s) %s\n", sqlite3_query, sqlite3_errmsg(db)); fprintf(stderr, "ERROR: SQLite: (%s) %s\n", sqlite3_query, sqlite3_errmsg(db));
return 3; return 3;

View File

@ -178,49 +178,6 @@ char* resolveFilePath(sqlite3 *db, long id, char *buffer) {
return 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) { void detachRepositoryDatabases(struct configTag* ct, sqlite3 *db, char* arch, int source) {
char sql[PATH_MAX]; char sql[PATH_MAX];
char *errmsg; char *errmsg;
@ -838,7 +795,7 @@ void printSpecialQueryResponse() {
if (!ct) return; if (!ct) return;
db = openRepositoryDatabase(ct); db = openRepositoryDatabase(ct);
if (!db) return; if (!db) return;
attachCtDatabases(ct, db, NULL); attachCtDatabases(ct, db);
if (ct->arch[0]) { if (ct->arch[0]) {
dbb = openRepositoryDatabase(ct); dbb = openRepositoryDatabase(ct);

View File

@ -67,6 +67,49 @@ sqlite3* openRepositoryDatabase(struct configTag* ct, string arch, string append
return db; 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) { int sqlite3_find_column_id(sqlite3_stmt *stmt, const char* table, const char* name) {
const char* colname; const char* colname;
int id = 0; int id = 0;
@ -83,3 +126,34 @@ int sqlite3_find_column_id(sqlite3_stmt *stmt, const char* table, const char* na
} }
return -1; 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<char>(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;
}

View File

@ -29,7 +29,11 @@ using namespace std;
string rpmSenseFlagsToString(int flags); string rpmSenseFlagsToString(int flags);
vector<string> split(string str, string token); vector<string> split(string str, string token);
sqlite3* openRepositoryDatabase(struct configTag* ct, string arch = "", string append = ""); 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); 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 HDSIZE 16
#define SSSIZE 24 #define SSSIZE 24