aboutsummaryrefslogblamecommitdiffstats
path: root/src/delete.c
blob: 1e5a5ed8064328aa603858abad7e780ea30ecb55 (plain) (tree)
1
2
3
4
5
6
7
8
9
10





                                                                                
                                          


                                                                                

                   
                    
































































































































                                                                                              
                                                                                   








































                                                                    









































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