view deita/d_sqlite.c @ 188:32ce881452fa hg-web

Fixing few stuff.
author MrJuneJune <me@mrjunejune.com>
date Fri, 23 Jan 2026 22:50:28 -0800
parents ae6a88e6e484
children
line wrap: on
line source

#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;
  }
}