/* delete.c - the delete action ----------------------------------------*- C -*-
*
* This file is part of ck, the config keeper
*
* -----------------------------------------------------------------------------
*
* Copyright (C) 2019 Anastasis Grammenos
* GPLv3 (see LICENCE for the full notice)
*
* -------------------------------------------------------------------------- */
#include <libgen.h>
#include "dblayer.h"
#include "ckerrlog.h"
ERRLOG(delete);
static int delete_prog(DB *db, int pid) {
sqlite3_stmt *stmt;
int rc;
char sql[STR_M] = "";
dbh_fq_delete_x_from_y(sql, COL_PROGRAM_ID, TBL_PROGRAM);
rc = sqlite3_prepare_v2(db->ptr, sql, -1, &stmt, 0);
if (rc != SQLITE_OK) {
return -1;
}
sqlite3_bind_int(stmt, 1, pid);
sqlite3_step(stmt);
if (rc != SQLITE_OK) {
return -1;
}
sqlite3_finalize(stmt);
return 0;
}
static int delete_conf(DB *db, int cid) {
sqlite3_stmt *stmt;
int rc;
char sql[STR_M] = "";
dbh_fq_delete_x_from_y(sql, COL_CONFIG_ID, TBL_CONFIG);
rc = sqlite3_prepare_v2(db->ptr, sql, -1, &stmt, 0);
if (rc != SQLITE_OK) {
return -1;
}
sqlite3_bind_int(stmt, 1, cid);
sqlite3_step(stmt);
if (rc != SQLITE_OK) {
return -1;
}
sqlite3_finalize(stmt);
return 0;
}
/* Removes the relationship of `cid` with the corresponding program.
* Returns the program's pid on succes, negative integer otherwise.
*/
static int remove_conf_rel(DB *db, int cid) {
sqlite3_stmt *stmt;
int rc;
int pid = get_pid_from_cid(db, cid);
char sql[STR_M] = "";
dbh_fq_delete_x_from_y(sql, COL_REL_CONFIG_ID, TBL_REL);
rc = sqlite3_prepare_v2(db->ptr, sql, -1, &stmt, 0);
if (rc != SQLITE_OK) {
return -1;
}
sqlite3_bind_int(stmt, 1, cid);
sqlite3_step(stmt);
if (rc != SQLITE_OK) {
return -1;
}
sqlite3_finalize(stmt);
return pid;
}
static int remove_all_configs(DB *db, int pid) {
sqlite3_stmt *stmt;
int rc;
char sql[STR_M] = "";
dbh_fq_select_from_joined_eq(sql, COL_REL_CONFIG_ID, COL_REL_PROGRAM_ID);
rc = sqlite3_prepare_v2(db->ptr, sql, -1, &stmt, 0);
if (rc != SQLITE_OK) {
return -2;
}
sqlite3_bind_int(stmt, 1, pid);
while (sqlite3_step(stmt) == SQLITE_ROW) {
delete_conf(db, sqlite3_column_int(stmt, 0));
remove_conf_rel(db, sqlite3_column_int(stmt, 0));
}
sqlite3_finalize(stmt);
return 0;
}
static int get_cid_from_pname_and_basename(DB *db, const char *pName, const char *cBaseName) {
sqlite3_stmt *stmt;
int rc;
char sql[STR_L] = "";
char selection[STR_M] = TBL_CONFIG;
strcat(selection, ".");
strcat(selection, COL_CONFIG_ID);
strcat(selection, ", ");
strcat(selection, COL_CONFIG_PATH);
char condition[STR_M] = TBL_PROGRAM;
strcat(condition, ".");
strcat(condition, COL_PROGRAM_NAME);
dbh_fq_select_from_joined_eq(sql, selection, condition);
rc = sqlite3_prepare_v2(db->ptr, sql, -1, &stmt, 0);
if (rc != SQLITE_OK) {
ERR("while preparing get_cid_from_pname_and_basename");
db->error = SQL_ERR_SQLITE;
return -1;
}
sqlite3_bind_text(stmt, 1, pName, -1, 0);
int _cid = -1;
while (sqlite3_step(stmt) == SQLITE_ROW) {
if (strcmp(cBaseName, basename((char *)sqlite3_column_text(stmt, 1))) == 0) {
_cid = sqlite3_column_int(stmt, 0);
break;
}
}
sqlite3_finalize(stmt);
return _cid;
}
static int del_transaction_try(DB *db, const char *pName, const char *cBaseName) {
__BEGIN_TRANSACTION__
int pid = -1;
if (cBaseName) {
// del conf
int cid = get_cid_from_pname_and_basename(db, pName, cBaseName);
if (cid < 0) {
ERR("Config %s doesn't exist in the database.", cBaseName);
return -1;
}
if (delete_conf(db, cid)) {
ERR("Could not delete config %s from db.", cBaseName);
return -1;
}
// handle relations
pid = remove_conf_rel(db, cid);
HELP("Deleted %s config: %s", pName, cBaseName);
if (get_program_relations(db, pid) > 0) {
goto end;
}
}
else {
pid = get_program_id(db, pName);
}
if (pid < 0) {
ERR("Program not found in the db.");
return -1;
}
/* If we are deleting a program we should delete everything that
* refferences it (configs and relationships) */
if (!cBaseName) {
remove_all_configs(db, pid);
}
if(delete_prog(db, pid)) {
ERR("Could not delete program %s from db.", pName);
return -1;
}
HELP("Deleted program %s", pName);
end:
__END_TRANSACTION__
return 0;
}
int run_DEL(UserOpt * opt, Conf *conf) {
UNUSED(conf);
DB db;
if (open_DB(&db, opt)) {
return -1;
}
int rc = -1;
/* Since we are here, args have to be 1 or 2 */
char *pName = list_get(opt->args);
if (!program_exists(&db, pName)) {
ERR("Program %s doesn't exist in the database.", pName);
goto error;
}
/* If there is no next argument */
if (!list_next(opt->args)) {
rc = del_transaction_try(&db, pName, NULL);
}
/* If there are more arguments */
else {
char *cName = list_get(opt->args);
rc = del_transaction_try(&db, pName, cName);
if (rc) {
HELP("Program %s doesn't have a config named %s", pName, cName);
print_suggested_configs(&db, pName);
}
}
error:
close_DB(&db);
if (!rc) {
hLOG("ckdb updated succesfully.");
} else {
sERR("Could not complete delete transaction.");
}
return rc;
}
void print_DEL_help() {
HELP("ck delete PROGRAM_NAME [CONFIG_BASENAME]");
}