107 lines
3.3 KiB
C
Raw Normal View History

#include "db.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static sqlite3 *db = NULL;
bool db_init(const char *db_path) {
if (sqlite3_open_v2(db_path, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL) != SQLITE_OK) {
fprintf(stderr, "Error opening database: %s\n", sqlite3_errmsg(db));
return false;
}
// Enable WAL mode for better concurrency
char *err_msg = NULL;
if (sqlite3_exec(db, "PRAGMA journal_mode=WAL;", NULL, NULL, &err_msg) != SQLITE_OK) {
fprintf(stderr, "Failed to set WAL mode: %s\n", err_msg);
sqlite3_free(err_msg);
// Not fatal
}
const char *schema_sql =
"CREATE TABLE IF NOT EXISTS history ("
" id INTEGER PRIMARY KEY AUTOINCREMENT,"
" command TEXT NOT NULL,"
" cwd TEXT NOT NULL,"
" exit_code INTEGER NOT NULL,"
" duration INTEGER NOT NULL,"
" hostname TEXT NOT NULL,"
" username TEXT NOT NULL,"
" shell TEXT NOT NULL,"
" session TEXT NOT NULL,"
" timestamp INTEGER NOT NULL,"
" created_at DATETIME DEFAULT CURRENT_TIMESTAMP,"
" updated_at DATETIME DEFAULT CURRENT_TIMESTAMP"
");"
"CREATE INDEX IF NOT EXISTS idx_timestamp ON history(timestamp DESC);"
"CREATE INDEX IF NOT EXISTS idx_exit_code ON history(exit_code);"
"CREATE INDEX IF NOT EXISTS idx_hostname ON history(hostname);"
"CREATE INDEX IF NOT EXISTS idx_cwd ON history(cwd);";
if (sqlite3_exec(db, schema_sql, NULL, NULL, &err_msg) != SQLITE_OK) {
fprintf(stderr, "Schema creation failed: %s\n", err_msg);
sqlite3_free(err_msg);
sqlite3_close(db);
db = NULL;
return false;
}
return true;
}
void db_close(void) {
if (db) {
sqlite3_close(db);
db = NULL;
}
}
sqlite3 *db_get_conn(void) {
return db;
}
bool db_add_history(const HistoryEntry *entry) {
if (!db) return false;
const char *sql = "INSERT INTO history "
"(command, cwd, exit_code, duration, hostname, username, shell, session, timestamp) "
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);";
sqlite3_stmt *stmt;
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) {
fprintf(stderr, "Prepare failed: %s\n", sqlite3_errmsg(db));
return false;
}
sqlite3_bind_text(stmt, 1, entry->command, -1, SQLITE_STATIC);
sqlite3_bind_text(stmt, 2, entry->cwd, -1, SQLITE_STATIC);
sqlite3_bind_int(stmt, 3, entry->exit_code);
sqlite3_bind_int(stmt, 4, entry->duration);
sqlite3_bind_text(stmt, 5, entry->hostname, -1, SQLITE_STATIC);
sqlite3_bind_text(stmt, 6, entry->username, -1, SQLITE_STATIC);
sqlite3_bind_text(stmt, 7, entry->shell, -1, SQLITE_STATIC);
sqlite3_bind_text(stmt, 8, entry->session, -1, SQLITE_STATIC);
sqlite3_bind_int64(stmt, 9, entry->timestamp);
int rc = sqlite3_step(stmt);
sqlite3_finalize(stmt);
if (rc != SQLITE_DONE) {
fprintf(stderr, "Insert failed: %s\n", sqlite3_errmsg(db));
return false;
}
return true;
}
void db_free_entry(HistoryEntry *entry) {
if (!entry) return;
free(entry->command);
free(entry->cwd);
free(entry->hostname);
free(entry->username);
free(entry->shell);
free(entry->session);
free(entry);
}