diff deita/d_sqlite.c @ 75:ae6a88e6e484

[Deita] Simple DB connection lib.
author June Park <parkjune1995@gmail.com>
date Wed, 31 Dec 2025 11:20:08 -0800
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/deita/d_sqlite.c	Wed Dec 31 11:20:08 2025 -0800
@@ -0,0 +1,327 @@
+#include "deita_internal.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+Deita_Connection* deita__sqlite_connection_create(const char *connection_string)
+{
+  Deita_Connection *p_connection = (Deita_Connection*)malloc(sizeof(Deita_Connection));
+  if (!p_connection)
+  {
+    fprintf(stderr, "deita__sqlite_connection_create: Failed to allocate connection\n");
+    return NULL;
+  }
+
+  p_connection->database_type = DEITA_DATABASE_TYPE_SQLITE3;
+  p_connection->native_handle = NULL;
+  p_connection->is_open = FALSE;
+
+  sqlite3 *p_db = NULL;
+  int32 result = sqlite3_open(connection_string, &p_db);
+
+  if (result != SQLITE_OK)
+  {
+    fprintf(stderr, "deita__sqlite_connection_create: Failed to open database: %s\n", sqlite3_errmsg(p_db));
+    sqlite3_close(p_db);
+    free(p_connection);
+    return NULL;
+  }
+
+  p_connection->native_handle = p_db;
+  p_connection->is_open = TRUE;
+
+  return p_connection;
+}
+
+void deita__sqlite_connection_close(Deita_Connection *p_connection)
+{
+  if (!p_connection)
+    return;
+
+  if (p_connection->native_handle)
+  {
+    sqlite3 *p_db = (sqlite3*)p_connection->native_handle;
+    sqlite3_close(p_db);
+    p_connection->native_handle = NULL;
+  }
+
+  p_connection->is_open = FALSE;
+  free(p_connection);
+}
+
+boolean deita__sqlite_connection_is_open(Deita_Connection *p_connection)
+{
+  if (!p_connection)
+    return FALSE;
+
+  return p_connection->is_open;
+}
+
+Deita_Result_Set* deita__sqlite_query_execute(
+  Deita_Connection *p_connection,
+  const char *query,
+  Dowa_Arena *p_arena)
+{
+  if (!p_connection || !p_connection->native_handle || !query)
+    return NULL;
+
+  sqlite3 *p_db = (sqlite3*)p_connection->native_handle;
+  sqlite3_stmt *p_stmt = NULL;
+
+  int32 result = sqlite3_prepare_v2(p_db, query, -1, &p_stmt, NULL);
+  if (result != SQLITE_OK)
+  {
+    fprintf(stderr, "deita__sqlite_query_execute: Failed to prepare statement: %s\n", sqlite3_errmsg(p_db));
+    return NULL;
+  }
+
+  Deita_Result_Set *p_result_set = (Deita_Result_Set*)Dowa_Arena_Allocate(p_arena, sizeof(Deita_Result_Set));
+  if (!p_result_set)
+  {
+    fprintf(stderr, "deita__sqlite_query_execute: Failed to allocate result set\n");
+    sqlite3_finalize(p_stmt);
+    return NULL;
+  }
+
+  p_result_set->database_type = DEITA_DATABASE_TYPE_SQLITE3;
+  p_result_set->native_result = p_stmt;
+  p_result_set->column_count = sqlite3_column_count(p_stmt);
+  p_result_set->has_data = FALSE;
+  p_result_set->is_done = FALSE;
+
+  return p_result_set;
+}
+
+Deita_Result_Set* deita__sqlite_query_execute_prepared(
+  Deita_Connection *p_connection,
+  const char *query,
+  int32 parameter_count,
+  const char **parameter_values,
+  Dowa_Arena *p_arena)
+{
+  if (!p_connection || !p_connection->native_handle || !query)
+    return NULL;
+
+  sqlite3 *p_db = (sqlite3*)p_connection->native_handle;
+  sqlite3_stmt *p_stmt = NULL;
+
+  int32 result = sqlite3_prepare_v2(p_db, query, -1, &p_stmt, NULL);
+  if (result != SQLITE_OK)
+  {
+    fprintf(stderr, "deita__sqlite_query_execute_prepared: Failed to prepare statement: %s\n", sqlite3_errmsg(p_db));
+    return NULL;
+  }
+
+  for (int32 i = 0; i < parameter_count; i++)
+  {
+    result = sqlite3_bind_text(p_stmt, i + 1, parameter_values[i], -1, SQLITE_TRANSIENT);
+    if (result != SQLITE_OK)
+    {
+      fprintf(stderr, "deita__sqlite_query_execute_prepared: Failed to bind parameter %d: %s\n", i, sqlite3_errmsg(p_db));
+      sqlite3_finalize(p_stmt);
+      return NULL;
+    }
+  }
+
+  Deita_Result_Set *p_result_set = (Deita_Result_Set*)Dowa_Arena_Allocate(p_arena, sizeof(Deita_Result_Set));
+  if (!p_result_set)
+  {
+    fprintf(stderr, "deita__sqlite_query_execute_prepared: Failed to allocate result set\n");
+    sqlite3_finalize(p_stmt);
+    return NULL;
+  }
+
+  p_result_set->database_type = DEITA_DATABASE_TYPE_SQLITE3;
+  p_result_set->native_result = p_stmt;
+  p_result_set->column_count = sqlite3_column_count(p_stmt);
+  p_result_set->has_data = FALSE;
+  p_result_set->is_done = FALSE;
+
+  return p_result_set;
+}
+
+int32 deita__sqlite_query_execute_update(
+  Deita_Connection *p_connection,
+  const char *query)
+{
+  if (!p_connection || !p_connection->native_handle || !query)
+    return -1;
+
+  sqlite3 *p_db = (sqlite3*)p_connection->native_handle;
+  char *error_message = NULL;
+
+  int32 result = sqlite3_exec(p_db, query, NULL, NULL, &error_message);
+  if (result != SQLITE_OK)
+  {
+    fprintf(stderr, "deita__sqlite_query_execute_update: Failed to execute: %s\n", error_message);
+    sqlite3_free(error_message);
+    return -1;
+  }
+
+  return sqlite3_changes(p_db);
+}
+
+int32 deita__sqlite_query_execute_update_prepared(
+  Deita_Connection *p_connection,
+  const char *query,
+  int32 parameter_count,
+  const char **parameter_values)
+{
+  if (!p_connection || !p_connection->native_handle || !query)
+    return -1;
+
+  sqlite3 *p_db = (sqlite3*)p_connection->native_handle;
+  sqlite3_stmt *p_stmt = NULL;
+
+  int32 result = sqlite3_prepare_v2(p_db, query, -1, &p_stmt, NULL);
+  if (result != SQLITE_OK)
+  {
+    fprintf(stderr, "deita__sqlite_query_execute_update_prepared: Failed to prepare statement: %s\n", sqlite3_errmsg(p_db));
+    return -1;
+  }
+
+  for (int32 i = 0; i < parameter_count; i++)
+  {
+    result = sqlite3_bind_text(p_stmt, i + 1, parameter_values[i], -1, SQLITE_TRANSIENT);
+    if (result != SQLITE_OK)
+    {
+      fprintf(stderr, "deita__sqlite_query_execute_update_prepared: Failed to bind parameter %d: %s\n", i, sqlite3_errmsg(p_db));
+      sqlite3_finalize(p_stmt);
+      return -1;
+    }
+  }
+
+  result = sqlite3_step(p_stmt);
+  if (result != SQLITE_DONE)
+  {
+    fprintf(stderr, "deita__sqlite_query_execute_update_prepared: Failed to execute: %s\n", sqlite3_errmsg(p_db));
+    sqlite3_finalize(p_stmt);
+    return -1;
+  }
+
+  int32 changes = sqlite3_changes(p_db);
+  sqlite3_finalize(p_stmt);
+
+  return changes;
+}
+
+boolean deita__sqlite_result_set_next(Deita_Result_Set *p_result_set)
+{
+  if (!p_result_set || !p_result_set->native_result || p_result_set->is_done)
+    return FALSE;
+
+  sqlite3_stmt *p_stmt = (sqlite3_stmt*)p_result_set->native_result;
+  int32 result = sqlite3_step(p_stmt);
+
+  if (result == SQLITE_ROW)
+  {
+    p_result_set->has_data = TRUE;
+    return TRUE;
+  }
+  else if (result == SQLITE_DONE)
+  {
+    p_result_set->has_data = FALSE;
+    p_result_set->is_done = TRUE;
+    return FALSE;
+  }
+  else
+  {
+    fprintf(stderr, "deita__sqlite_result_set_next: Error stepping through results\n");
+    p_result_set->has_data = FALSE;
+    p_result_set->is_done = TRUE;
+    return FALSE;
+  }
+}
+
+int32 deita__sqlite_result_set_get_column_count(Deita_Result_Set *p_result_set)
+{
+  if (!p_result_set)
+    return 0;
+
+  return p_result_set->column_count;
+}
+
+const char* deita__sqlite_result_set_get_column_name(
+  Deita_Result_Set *p_result_set,
+  int32 column_index)
+{
+  if (!p_result_set || !p_result_set->native_result)
+    return NULL;
+
+  sqlite3_stmt *p_stmt = (sqlite3_stmt*)p_result_set->native_result;
+  return sqlite3_column_name(p_stmt, column_index);
+}
+
+Deita_Column_Type deita__sqlite_result_set_get_column_type(
+  Deita_Result_Set *p_result_set,
+  int32 column_index)
+{
+  if (!p_result_set || !p_result_set->native_result)
+    return DEITA_COLUMN_TYPE_NULL;
+
+  sqlite3_stmt *p_stmt = (sqlite3_stmt*)p_result_set->native_result;
+  int32 sqlite_type = sqlite3_column_type(p_stmt, column_index);
+
+  switch (sqlite_type)
+  {
+    case SQLITE_INTEGER:
+      return DEITA_COLUMN_TYPE_INTEGER;
+    case SQLITE_FLOAT:
+      return DEITA_COLUMN_TYPE_REAL;
+    case SQLITE_TEXT:
+      return DEITA_COLUMN_TYPE_TEXT;
+    case SQLITE_BLOB:
+      return DEITA_COLUMN_TYPE_BLOB;
+    case SQLITE_NULL:
+    default:
+      return DEITA_COLUMN_TYPE_NULL;
+  }
+}
+
+const char* deita__sqlite_result_set_get_text(
+  Deita_Result_Set *p_result_set,
+  int32 column_index)
+{
+  if (!p_result_set || !p_result_set->native_result)
+    return NULL;
+
+  sqlite3_stmt *p_stmt = (sqlite3_stmt*)p_result_set->native_result;
+  const unsigned char *text = sqlite3_column_text(p_stmt, column_index);
+
+  return (const char*)text;
+}
+
+int64 deita__sqlite_result_set_get_integer(
+  Deita_Result_Set *p_result_set,
+  int32 column_index)
+{
+  if (!p_result_set || !p_result_set->native_result)
+    return 0;
+
+  sqlite3_stmt *p_stmt = (sqlite3_stmt*)p_result_set->native_result;
+  return sqlite3_column_int64(p_stmt, column_index);
+}
+
+double deita__sqlite_result_set_get_real(
+  Deita_Result_Set *p_result_set,
+  int32 column_index)
+{
+  if (!p_result_set || !p_result_set->native_result)
+    return 0.0;
+
+  sqlite3_stmt *p_stmt = (sqlite3_stmt*)p_result_set->native_result;
+  return sqlite3_column_double(p_stmt, column_index);
+}
+
+void deita__sqlite_result_set_free(Deita_Result_Set *p_result_set)
+{
+  if (!p_result_set)
+    return;
+
+  if (p_result_set->native_result)
+  {
+    sqlite3_stmt *p_stmt = (sqlite3_stmt*)p_result_set->native_result;
+    sqlite3_finalize(p_stmt);
+    p_result_set->native_result = NULL;
+  }
+}