#include "database.h" #include sqlite3 * database_connect (const char *path) { sqlite3 *db; gchar *file = g_build_filename (path, "cards.db", NULL); int rc = sqlite3_open (file, &db); if (rc) { fprintf (stderr, "Can't open database: %s\n", sqlite3_errmsg (db)); return nullptr; } fprintf (stdout, "Opened database successfully\n"); g_free (file); database_create_tables (db); return db; } void database_close (sqlite3 *db) { sqlite3_close (db); } void database_create_tables (sqlite3 *db) { sqlite3_stmt *stmt; const char *sql = "CREATE TABLE IF NOT EXISTS `cards` (" "`id` INTEGER NOT NULL," "`category` INTEGER NOT NULL," "`title` TEXT NOT NULL," "`answer` TEXT NOT NULL," "`next_time` INTEGER NOT NULL DEFAULT (unixepoch())," "PRIMARY KEY(`id` AUTOINCREMENT)" ")"; int rc = sqlite3_prepare_v2 (db, sql, -1, &stmt, nullptr); if (rc != SQLITE_OK) fprintf (stderr, "Failed to execute statement: %s\n", sqlite3_errmsg (db)); sqlite3_step (stmt); sqlite3_finalize (stmt); sql = "CREATE TABLE IF NOT EXISTS `categories` (" "`id` INTEGER NOT NULL," "`name` TEXT NOT NULL," "PRIMARY KEY(`id` AUTOINCREMENT)" ")"; rc = sqlite3_prepare_v2 (db, sql, -1, &stmt, nullptr); if (rc != SQLITE_OK) fprintf (stderr, "Failed to execute statement: %s\n", sqlite3_errmsg (db)); sqlite3_step (stmt); sqlite3_finalize (stmt); } void database_save_category (sqlite3 *db, const char *c) { sqlite3_stmt *stmt; fprintf (stdout, "%s\n", c); int rc = sqlite3_prepare_v2 (db, "INSERT INTO categories (name) VALUES(?)", -1, &stmt, nullptr); if (rc == SQLITE_OK) sqlite3_bind_text (stmt, 1, c, -1, SQLITE_STATIC); else printf ("Failed to execute statement: %s\n", sqlite3_errmsg (db)); rc = sqlite3_step (stmt); if (rc != SQLITE_DONE) { fprintf (stderr, "Failed to execute statement: %s\n", sqlite3_errmsg (db)); } sqlite3_finalize (stmt); } GArray * database_load_categories (sqlite3 *db) { sqlite3_stmt *stmt; GArray *categories = g_array_new (TRUE, FALSE, sizeof (category)); int rc = sqlite3_prepare_v2 (db, "SELECT * FROM categories", -1, &stmt, nullptr); if (rc != SQLITE_OK) fprintf (stderr, "Failed to execute statement: %s\n", sqlite3_errmsg (db)); while (sqlite3_step (stmt) == SQLITE_ROW) { category c; c.id = sqlite3_column_int (stmt, 0); c.name = strdup ((char *)sqlite3_column_text (stmt, 1)); g_array_append_val (categories, c); } sqlite3_finalize (stmt); return categories; } void database_delete_category (sqlite3 *db, const int id) { // delete all cards in the category sqlite3_stmt *stmt; int rc = sqlite3_prepare_v2 (db, "DELETE FROM cards WHERE category = ?", -1, &stmt, nullptr); if (rc == SQLITE_OK) sqlite3_bind_int (stmt, 1, id); else fprintf (stderr, "Failed to execute statement: %s\n", sqlite3_errmsg (db)); rc = sqlite3_step (stmt); if (rc != SQLITE_DONE) fprintf (stderr, "Execution failed: %s\n", sqlite3_errmsg (db)); sqlite3_finalize (stmt); // delete the category rc = sqlite3_prepare_v2 (db, "DELETE FROM categories WHERE id = ?", -1, &stmt, nullptr); if (rc == SQLITE_OK) sqlite3_bind_int (stmt, 1, id); else fprintf (stderr, "Failed to execute statement: %s\n", sqlite3_errmsg (db)); rc = sqlite3_step (stmt); if (rc != SQLITE_DONE) fprintf (stderr, "Execution failed: %s\n", sqlite3_errmsg (db)); sqlite3_finalize (stmt); } void database_save_card (sqlite3 *db, const int category, const char *title, const char *answer) { sqlite3_stmt *stmt; int rc = sqlite3_prepare_v2 ( db, "INSERT INTO cards (category, title, answer) VALUES(?, ?, ?)", -1, &stmt, nullptr); if (rc == SQLITE_OK) { sqlite3_bind_int (stmt, 1, category); sqlite3_bind_text (stmt, 2, title, -1, SQLITE_STATIC); sqlite3_bind_text (stmt, 3, answer, -1, SQLITE_STATIC); } else fprintf (stderr, "Failed to execute statement: %s\n", sqlite3_errmsg (db)); rc = sqlite3_step (stmt); if (rc != SQLITE_DONE) fprintf (stderr, "Execution failed: %s\n", sqlite3_errmsg (db)); sqlite3_finalize (stmt); } GArray * database_load_cards (sqlite3 *db, const int category) { GArray *cards = g_array_new (TRUE, FALSE, sizeof (card)); sqlite3_stmt *stmt; int rc = sqlite3_prepare_v2 (db, "SELECT * FROM cards WHERE category = ? AND " "next_time <= unixepoch() ORDER BY next_time ASC", -1, &stmt, nullptr); if (rc == SQLITE_OK) sqlite3_bind_int (stmt, 1, category); else fprintf (stderr, "Failed to execute statement: %s\n", sqlite3_errmsg (db)); while (sqlite3_step (stmt) == SQLITE_ROW) { card c; c.id = sqlite3_column_int (stmt, 0); c.category = sqlite3_column_int (stmt, 1); c.title = strdup ((char *)sqlite3_column_text (stmt, 2)); c.answer = strdup ((char *)sqlite3_column_text (stmt, 3)); c.next_time = g_date_time_new_from_unix_utc (sqlite3_column_int64 (stmt, 4)); g_array_append_val (cards, c); } sqlite3_finalize (stmt); return cards; } void database_schedule_card (sqlite3 *db, const int id, GDateTime *next_time) { sqlite3_stmt *stmt; int rc = sqlite3_prepare_v2 ( db, "UPDATE cards SET next_time = ? WHERE id = ?", -1, &stmt, nullptr); if (rc == SQLITE_OK) { sqlite3_bind_int64 (stmt, 1, g_date_time_to_unix (next_time)); sqlite3_bind_int (stmt, 2, id); } else fprintf (stderr, "Failed to execute statement: %s\n", sqlite3_errmsg (db)); rc = sqlite3_step (stmt); if (rc != SQLITE_DONE) fprintf (stderr, "Execution failed: %s\n", sqlite3_errmsg (db)); sqlite3_finalize (stmt); } void database_delete_card (sqlite3 *db, const int id) { sqlite3_stmt *stmt; int rc = sqlite3_prepare_v2 (db, "DELETE FROM cards WHERE id = ?", -1, &stmt, nullptr); if (rc == SQLITE_OK) sqlite3_bind_int (stmt, 1, id); else fprintf (stderr, "Failed to execute statement: %s\n", sqlite3_errmsg (db)); rc = sqlite3_step (stmt); if (rc != SQLITE_DONE) fprintf (stderr, "Execution failed: %s\n", sqlite3_errmsg (db)); sqlite3_finalize (stmt); }