changeset 3923:e9d45ec624cb HEAD

Forgot to add in sqlite patch.
author Timo Sirainen <tss@iki.fi>
date Sun, 22 Jan 2006 14:57:03 +0200
parents 344e4a729318
children 8297377a569b
files src/lib-sql/driver-sqlite.c
diffstat 1 files changed, 382 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-sql/driver-sqlite.c	Sun Jan 22 14:57:03 2006 +0200
@@ -0,0 +1,382 @@
+/* Copyright (C) 2006 Jakob Hirsch */
+
+#include "lib.h"
+#include "str.h"
+#include "sql-api-private.h"
+
+#ifdef HAVE_SQLITE
+#include <stdlib.h>
+#include <time.h>
+#include <sqlite3.h>
+
+/* retry time if db is busy (in ms) */
+const int sqlite_busy_timeout = 1000;
+
+struct sqlite_db {
+	struct sql_db api;
+
+	pool_t pool;
+	const char *dbfile;
+	sqlite3 *sqlite;
+	unsigned int connected:1;
+	int rc;
+};
+
+struct sqlite_result {
+	struct sql_result api;
+	sqlite3_stmt *stmt;
+	unsigned int cols;
+	const char **row;
+};
+
+struct sqlite_transaction_context {
+	struct sql_transaction_context ctx;
+	unsigned int failed:1;
+};
+
+extern struct sql_result driver_sqlite_result;
+extern struct sql_result driver_sqlite_error_result;
+
+static int driver_sqlite_connect(struct sql_db *_db)
+{
+ 	struct sqlite_db *db = (struct sqlite_db *)_db;
+  
+	if (db->connected)
+		return 1;
+
+	db->rc = sqlite3_open(db->dbfile, &db->sqlite);
+	
+	if (db->rc == SQLITE_OK) {
+		db->connected = TRUE;
+		sqlite3_busy_timeout(db->sqlite, sqlite_busy_timeout);
+		return 1;
+	} else {
+		i_error("sqlite: open(%s) failed: %s", db->dbfile,
+			sqlite3_errmsg(db->sqlite));
+		sqlite3_close(db->sqlite);
+		return -1;
+	}
+}
+
+static struct sql_db *driver_sqlite_init(const char *connect_string)
+{
+	struct sqlite_db *db;
+	pool_t pool;
+
+	i_assert(connect_string != NULL);
+
+	pool = pool_alloconly_create("sqlite driver", 512);
+	db = p_new(pool, struct sqlite_db, 1);
+	db->pool = pool;
+	db->api = driver_sqlite_db;
+	db->dbfile = p_strdup(db->pool, connect_string);
+	db->connected = FALSE;
+
+	return &db->api;
+}
+
+static void driver_sqlite_deinit(struct sql_db *_db)
+{
+	struct sqlite_db *db = (struct sqlite_db *)_db;
+
+	sqlite3_close(db->sqlite);
+	pool_unref(db->pool);
+}
+
+static enum sql_db_flags
+driver_sqlite_get_flags(struct sql_db *db __attr_unused__)
+{
+	return SQL_DB_FLAG_BLOCKING;
+}
+
+static void driver_sqlite_exec(struct sql_db *_db, const char *query)
+{
+	struct sqlite_db *db = (struct sqlite_db *)_db;
+
+	db->rc = sqlite3_exec(db->sqlite, query, NULL, 0, NULL);
+	if (db->rc != SQLITE_OK) {
+		i_error("sqlite: exec(%s) failed: %s (%d)",
+			query, sqlite3_errmsg(db->sqlite), db->rc);
+	}
+}
+
+static void driver_sqlite_query(struct sql_db *db, const char *query,
+			       sql_query_callback_t *callback, void *context)
+{
+	struct sql_result *result;
+
+	result = sql_query_s(db, query);
+	result->callback = TRUE;
+	callback(result, context);
+	sql_result_free(result);
+}
+
+static struct sql_result *
+driver_sqlite_query_s(struct sql_db *_db, const char *query)
+{
+	struct sqlite_db *db = (struct sqlite_db *)_db;
+	struct sqlite_result *result;
+	int rc;
+
+	result = i_new(struct sqlite_result, 1);
+
+	rc = sqlite3_prepare(db->sqlite, query, -1, &result->stmt, NULL);
+	if (rc == SQLITE_OK) {
+		result->api = driver_sqlite_result;
+		result->cols = sqlite3_column_count(result->stmt);
+		result->row = i_new(const char *, result->cols);
+	} else {
+		result->api = driver_sqlite_error_result;
+		result->stmt = NULL;
+		result->cols = 0;
+	}
+	result->api.db = _db;
+
+	return &result->api;
+}
+
+static void driver_sqlite_result_free(struct sql_result *_result)
+{
+	struct sqlite_result *result = (struct sqlite_result *)_result;
+	struct sqlite_db *db = (struct sqlite_db *)	result->api.db;
+	int rc;
+
+	if (result->stmt != NULL) {
+		if ((rc = sqlite3_finalize(result->stmt)) != SQLITE_OK) {
+			i_warning("sqlite: finalize failed: %s (%d)",
+				  sqlite3_errmsg(db->sqlite), rc);
+		}
+		i_free(result->row);
+	}
+	i_free(result);
+}
+
+static int driver_sqlite_result_next_row(struct sql_result *_result)
+{
+	struct sqlite_result *result = (struct sqlite_result *)_result;
+
+	switch (sqlite3_step(result->stmt)) {
+	case SQLITE_ROW:
+		return 1;
+	case SQLITE_DONE:
+		return 0;
+	default:
+		return -1;
+	}
+}
+
+static unsigned int
+driver_sqlite_result_get_fields_count(struct sql_result *_result)
+{
+	struct sqlite_result *result = (struct sqlite_result *)_result;
+
+	return result->cols;
+}
+
+static const char *
+driver_sqlite_result_get_field_name(struct sql_result *_result,
+				    unsigned int idx)
+{
+	struct sqlite_result *result = (struct sqlite_result *)_result;
+
+	return sqlite3_column_name(result->stmt, idx);
+}
+
+static int driver_sqlite_result_find_field(struct sql_result *_result,
+					   const char *field_name)
+{
+	struct sqlite_result *result = (struct sqlite_result *)_result;
+	unsigned int i;
+
+	for (i = 0; i < result->cols; ++i) {
+		const char *col = sqlite3_column_name(result->stmt, i);
+
+		if (strcmp(col, field_name) == 0)
+			return i;
+	}
+	
+	return -1;
+}
+
+static const char *
+driver_sqlite_result_get_field_value(struct sql_result *_result,
+				    unsigned int idx)
+{
+	struct sqlite_result *result = (struct sqlite_result *)_result;
+
+	return sqlite3_column_text(result->stmt, idx);
+}
+
+static const char *
+driver_sqlite_result_find_field_value(struct sql_result *result,
+				     const char *field_name)
+{
+	int idx;
+
+	idx = driver_sqlite_result_find_field(result, field_name);
+	if (idx < 0)
+		return NULL;
+	return driver_sqlite_result_get_field_value(result, idx);
+}
+
+static const char *const *
+driver_sqlite_result_get_values(struct sql_result *_result)
+{
+	struct sqlite_result *result = (struct sqlite_result *)_result;
+	unsigned int i;
+
+	for (i = 0; i < result->cols; ++i) {
+		result->row[i] =
+			driver_sqlite_result_get_field_value(_result, i);
+	}
+
+	return (const char *const *)result->row;
+}
+
+static const char *driver_sqlite_result_get_error(struct sql_result *_result)
+{
+	struct sqlite_result *result = (struct sqlite_result *)_result;
+	struct sqlite_db *db = (struct sqlite_db *)result->api.db;
+
+	return sqlite3_errmsg(db->sqlite);
+}
+
+static struct sql_transaction_context *
+driver_sqlite_transaction_begin(struct sql_db *_db)
+{
+	struct sqlite_transaction_context *ctx;
+	struct sqlite_db *db = (struct sqlite_db *)_db;
+
+	ctx = i_new(struct sqlite_transaction_context, 1);
+	ctx->ctx.db = _db;
+
+	sql_exec(_db, "BEGIN TRANSACTION");
+	if (db->rc != SQLITE_OK)
+		ctx->failed = TRUE;
+
+	return &ctx->ctx;
+}
+
+static void
+driver_sqlite_transaction_rollback(struct sql_transaction_context *_ctx)
+{
+	struct sqlite_transaction_context *ctx =
+		(struct sqlite_transaction_context *)_ctx;
+
+	sql_exec(_ctx->db, "ROLLBACK");
+	i_free(ctx);
+}
+
+static void
+driver_sqlite_transaction_commit(struct sql_transaction_context *_ctx,
+				 sql_commit_callback_t *callback, void *context)
+{
+	struct sqlite_transaction_context *ctx =
+		(struct sqlite_transaction_context *)_ctx;
+	struct sqlite_db *db = (struct sqlite_db *)ctx->ctx.db;
+	const char *errmsg;
+
+	if (!ctx->failed) {
+		sql_exec(_ctx->db, "COMMIT");
+		if (db->rc != SQLITE_OK)
+			ctx->failed = TRUE;
+	}
+
+	if (ctx->failed) {
+		errmsg = sqlite3_errmsg(db->sqlite);
+		callback(errmsg, context);
+                /* also does i_free(ctx) */
+		driver_sqlite_transaction_rollback(_ctx);
+	} else {
+		callback(NULL, context);
+		i_free(ctx);
+	}
+}
+
+static int
+driver_sqlite_transaction_commit_s(struct sql_transaction_context *_ctx,
+				   const char **error_r)
+{
+	struct sqlite_transaction_context *ctx =
+		(struct sqlite_transaction_context *)_ctx;
+	struct sqlite_db *db = (struct sqlite_db *) ctx->ctx.db;
+
+	if (ctx->failed) {
+                /* also does i_free(ctx) */
+		driver_sqlite_transaction_rollback(_ctx);
+		return -1;
+	}
+
+	sql_exec(_ctx->db, "COMMIT");
+	*error_r = sqlite3_errmsg(db->sqlite);
+	i_free(ctx);
+	return 0;
+}
+
+static void
+driver_sqlite_update(struct sql_transaction_context *_ctx, const char *query)
+{
+	struct sqlite_transaction_context *ctx =
+		(struct sqlite_transaction_context *)_ctx;
+	struct sqlite_db *db = (struct sqlite_db *)ctx->ctx.db;
+
+	if (ctx->failed)
+		return;
+
+	sql_exec(_ctx->db, query);
+	if (db->rc != SQLITE_OK)
+		ctx->failed = TRUE;
+}
+
+struct sql_db driver_sqlite_db = {
+	"sqlite",
+
+	driver_sqlite_init,
+	driver_sqlite_deinit,
+	driver_sqlite_get_flags,
+	driver_sqlite_connect,
+	driver_sqlite_exec,
+	driver_sqlite_query,
+	driver_sqlite_query_s,
+
+	driver_sqlite_transaction_begin,
+	driver_sqlite_transaction_commit,
+	driver_sqlite_transaction_commit_s,
+	driver_sqlite_transaction_rollback,
+	driver_sqlite_update
+};
+
+struct sql_result driver_sqlite_result = {
+	NULL,
+
+	driver_sqlite_result_free,
+	driver_sqlite_result_next_row,
+	driver_sqlite_result_get_fields_count,
+	driver_sqlite_result_get_field_name,
+	driver_sqlite_result_find_field,
+	driver_sqlite_result_get_field_value,
+	driver_sqlite_result_find_field_value,
+	driver_sqlite_result_get_values,
+	driver_sqlite_result_get_error,
+
+	FALSE
+};
+
+static int
+driver_sqlite_result_error_next_row(struct sql_result *result __attr_unused__)
+{
+	return -1;
+}
+
+struct sql_result driver_sqlite_error_result = {
+	NULL,
+
+	driver_sqlite_result_free,
+	driver_sqlite_result_error_next_row,
+	NULL, NULL, NULL, NULL, NULL, NULL,
+	driver_sqlite_result_get_error,
+
+	FALSE
+};
+
+#endif