/* 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 #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_form_query_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_form_query_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_form_query_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_form_query_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_form_query_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]"); }