[dovecot-cvs] dovecot/src/lib-dict Makefile.am, 1.4, 1.5 dict-client.c, 1.12, 1.13 dict-client.h, 1.3, 1.4 dict-db.c, NONE, 1.1 dict-private.h, 1.5, 1.6 dict-sql.c, 1.11, 1.12 dict.c, 1.9, 1.10 dict.h, 1.6, 1.7

tss-movial at dovecot.org tss-movial at dovecot.org
Sun Jul 30 21:49:43 EEST 2006


Update of /var/lib/cvs/dovecot/src/lib-dict
In directory talvi:/tmp/cvs-serv14402/lib-dict

Modified Files:
	Makefile.am dict-client.c dict-client.h dict-private.h 
	dict-sql.c dict.c dict.h 
Added Files:
	dict-db.c 
Log Message:
Dictionary changes: Added support for defining value's type. Key is still always a string. Added support for sorting the iteration replies. Added dict_unset(). Added Berkeley DB support. Most of the code written by Tianyan Liu.



Index: Makefile.am
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-dict/Makefile.am,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- Makefile.am	14 Jan 2006 14:01:40 -0000	1.4
+++ Makefile.am	30 Jul 2006 18:49:38 -0000	1.5
@@ -9,10 +9,12 @@
 libdict_a_SOURCES = \
 	dict.c \
 	dict-client.c \
+	dict-db.c \
 	dict-sql.c
 
 noinst_HEADERS = \
 	dict.h \
 	dict-client.h \
 	dict-private.h \
+	dict-db.h \
 	dict-sql.h

Index: dict-client.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-dict/dict-client.c,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -d -r1.12 -r1.13
--- dict-client.c	30 Jul 2006 18:13:03 -0000	1.12
+++ dict-client.c	30 Jul 2006 18:49:38 -0000	1.13
@@ -19,6 +19,7 @@
 	const char *uri;
 	const char *username;
 	const char *path;
+	enum dict_data_type value_type;
 
 	struct istream *input;
 	struct ostream *output;
@@ -247,10 +248,11 @@
 	dict->transaction_id_counter = 0;
 
 	t_push();
-	query = t_strdup_printf("%c%u\t%u\t%s\t%s\n", DICT_PROTOCOL_CMD_HELLO,
+	query = t_strdup_printf("%c%u\t%u\t%d\t%s\t%s\n",
+				DICT_PROTOCOL_CMD_HELLO,
 				DICT_CLIENT_PROTOCOL_MAJOR_VERSION,
 				DICT_CLIENT_PROTOCOL_MINOR_VERSION,
-				dict->username, dict->uri);
+				dict->value_type, dict->username, dict->uri);
 	if (client_dict_send_query(dict, query) < 0) {
 		client_dict_disconnect(dict);
 		t_pop();
@@ -279,8 +281,9 @@
 	}
 }
 
-static struct dict *client_dict_init(struct dict *dict_class, const char *uri,
-				     const char *username)
+static struct dict *
+client_dict_init(struct dict *dict_class, const char *uri,
+		 enum dict_data_type value_type, const char *username)
 {
 	struct client_dict *dict;
 	const char *dest_uri;
@@ -297,6 +300,7 @@
 	dict = p_new(pool, struct client_dict, 1);
 	dict->pool = pool;
 	dict->dict = *dict_class;
+	dict->value_type = value_type;
 	dict->username = p_strdup(pool, username);
 
 	dict->fd = -1;
@@ -354,7 +358,8 @@
 }
 
 static struct dict_iterate_context *
-client_dict_iterate_init(struct dict *_dict, const char *path, bool recurse)
+client_dict_iterate_init(struct dict *_dict, const char *path, 
+			 enum dict_iterate_flags flags)
 {
 	struct client_dict *dict = (struct client_dict *)_dict;
         struct client_dict_iterate_context *ctx;
@@ -370,7 +375,7 @@
 
 	t_push();
 	query = t_strdup_printf("%c%d\t%s\n", DICT_PROTOCOL_CMD_ITERATE,
-				recurse, dict_client_escape(path));
+				flags, dict_client_escape(path));
 	if (client_dict_send_query(dict, query) < 0)
 		ctx->failed = TRUE;
 	t_pop();
@@ -501,6 +506,21 @@
 	t_pop();
 }
 
+static void client_dict_unset(struct dict_transaction_context *_ctx,
+			      const char *key)
+{
+	struct client_dict_transaction_context *ctx =
+		(struct client_dict_transaction_context *)_ctx;
+	const char *query;
+
+	t_push();
+	query = t_strdup_printf("%c%u\t%s\n",
+				DICT_PROTOCOL_CMD_UNSET, ctx->id,
+				dict_client_escape(key));
+	(void)client_dict_send_transaction_query(ctx, query);
+	t_pop();
+}
+
 static void client_dict_atomic_inc(struct dict_transaction_context *_ctx,
 				   const char *key, long long diff)
 {
@@ -530,6 +550,7 @@
 		client_dict_transaction_commit,
 		client_dict_transaction_rollback,
 		client_dict_set,
+		client_dict_unset,
 		client_dict_atomic_inc
 	}
 };

Index: dict-client.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-dict/dict-client.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- dict-client.h	17 Jun 2006 12:25:07 -0000	1.3
+++ dict-client.h	30 Jul 2006 18:49:38 -0000	1.4
@@ -3,23 +3,24 @@
 
 #define DEFAULT_DICT_SERVER_SOCKET_PATH PKG_RUNDIR"/dict-server"
 
-#define DICT_CLIENT_PROTOCOL_MAJOR_VERSION 1
+#define DICT_CLIENT_PROTOCOL_MAJOR_VERSION 2
 #define DICT_CLIENT_PROTOCOL_MINOR_VERSION 0
 
 #define DICT_CLIENT_MAX_LINE_LENGTH (64*1024)
 
 enum {
-        /* <major-version> <minor-version> <user> <dict name> */
+        /* <major-version> <minor-version> <value type> <user> <dict name> */
 	DICT_PROTOCOL_CMD_HELLO = 'H',
 
 	DICT_PROTOCOL_CMD_LOOKUP = 'L', /* <key> */
-	DICT_PROTOCOL_CMD_ITERATE = 'I', /* <recurse> <path> */
+	DICT_PROTOCOL_CMD_ITERATE = 'I', /* <flags> <path> */
 
 	DICT_PROTOCOL_CMD_BEGIN = 'B', /* <id> */
 	DICT_PROTOCOL_CMD_COMMIT = 'C', /* <id> */
 	DICT_PROTOCOL_CMD_ROLLBACK = 'R', /* <id> */
 
 	DICT_PROTOCOL_CMD_SET = 'S', /* <id> <key> <value> */
+	DICT_PROTOCOL_CMD_UNSET = 'U', /* <id> <key> */
 	DICT_PROTOCOL_CMD_ATOMIC_INC = 'A' /* <id> <key> <diff> */
 };
 

--- NEW FILE: dict-db.c ---
/* Copyright (C) 2006 PT.COM / SAPO. Code by Tianyan Liu */

#include "lib.h"
#include "dict-private.h"
#include "dict-db.h"

#include <stdlib.h>
#include <db.h>

struct db_dict {
	struct dict dict;
	enum dict_data_type value_type;
	pool_t pool;
	
	DB_ENV *db_env;
	DB *pdb;
	DB *sdb;
};

struct db_dict_iterate_context {
	struct dict_iterate_context ctx;
	pool_t pool;

	DBC *cursor;
	char *path;

	DBT pkey, pdata;

	int (*iterate_next)(struct db_dict_iterate_context *ctx,
			    const char **key_r, const char **value_r);

	enum dict_iterate_flags flags;
};

struct db_dict_transaction_context {
	struct dict_transaction_context ctx;

	DB_TXN *tid;
};

static void db_dict_deinit(struct dict *_dict);

static int associate_key(DB *pdb __attr_unused__,
			 const DBT *pkey __attr_unused__,
			 const DBT *pdata, DBT *skey)
{
	memset(skey, 0, sizeof(*skey));
	skey->data = pdata->data;
	skey->size = pdata->size;
	return 0;
}

static int uint32_t_compare(DB *db __attr_unused__,
			    const DBT *keya, const DBT *keyb)
{
	const uint32_t *ua = keya->data, *ub = keyb->data;

	return *ua > *ub ? 1 :
		(*ua < *ub ? -1 : 0);
}

static struct dict *db_dict_init(struct dict *dict_class, const char *uri,
				 enum dict_data_type value_type,
				 const char *username __attr_unused__)
{
	struct db_dict *dict;
	const char *hdir;
	DB_TXN *tid = NULL;
	pool_t pool;
	int ret;
	
	pool = pool_alloconly_create("db dict", 1024);
	dict = p_new(pool, struct db_dict, 1);
	dict->pool = pool;
	dict->dict = *dict_class;

	/* prepare the environment */
	ret = db_env_create(&dict->db_env, 0);
	if (ret != 0) {
		i_error("db_env:%s\n", db_strerror(ret));
		pool_unref(pool);
		return NULL;
	}

	dict->db_env->set_errfile(dict->db_env, stderr);
	dict->db_env->set_errpfx(dict->db_env, "db_env");

	hdir = strrchr(uri, '/');
	if (hdir != NULL)
		hdir = t_strndup(uri, hdir - uri);

	ret = dict->db_env->open(dict->db_env, hdir, DB_CREATE | 
				 DB_INIT_MPOOL | DB_INIT_TXN, 0);
	if (ret != 0) {
		pool_unref(pool);
		return NULL;
	}

	ret = dict->db_env->txn_begin(dict->db_env, NULL, &tid, 0);
	if (ret != 0) {
		pool_unref(pool);
		return NULL;
	}

	/* create both primary and secondary databases */
	ret = db_create(&dict->pdb, dict->db_env, 0);
	if (ret != 0) {
		i_error("primary db:%s\n", db_strerror(ret));
		db_dict_deinit(&dict->dict);
		return NULL;
	}
	dict->pdb->set_errfile(dict->pdb, stderr);
	dict->pdb->set_errpfx(dict->pdb, "primary db");

	ret = db_create(&dict->sdb, dict->db_env, 0);
	if (ret != 0) {
		i_error("secondary db:%s\n", db_strerror(ret));
		db_dict_deinit(&dict->dict);
		return NULL;
	}
	dict->pdb->set_errfile(dict->pdb, stderr);
	dict->pdb->set_errpfx(dict->pdb, "secondary db");

	if (dict->pdb->open(dict->pdb, tid, uri, NULL,
			    DB_BTREE, DB_CREATE, 0) != 0) {
		db_dict_deinit(&dict->dict);
		return NULL;
	}

	if (dict->sdb->set_flags(dict->sdb, DB_DUP) != 0) {
		db_dict_deinit(&dict->dict);
		return NULL;
	}
	
	/* by default db compare keys as if they are strings.
	   if we store uint32_t, then we need a customized
	   compare function */
	dict->value_type = value_type;
	if (value_type == DICT_DATA_TYPE_UINT32) {
		if (dict->sdb->set_bt_compare(dict->sdb,
					      uint32_t_compare) != 0) {
			db_dict_deinit(&dict->dict);
			return NULL;
		}
	}

	if (dict->sdb->open(dict->sdb, tid, NULL, NULL,
			    DB_BTREE, DB_CREATE, 0) != 0) {
		db_dict_deinit(&dict->dict);
		return NULL;
	}
	
	if (dict->pdb->associate(dict->pdb, tid, dict->sdb,
				 associate_key, DB_CREATE) != 0) {
		db_dict_deinit(&dict->dict);
		return NULL;
	}
	
	return &dict->dict;
}

static void db_dict_deinit(struct dict *_dict)
{
	struct db_dict *dict = (struct db_dict *)_dict;

	if (dict->pdb != NULL)
		dict->pdb->close(dict->pdb, 0);
	if (dict->sdb != NULL)
		dict->sdb->close(dict->sdb, 0);
	pool_unref(dict->pool);
}

static int db_dict_iterate_set(struct db_dict_iterate_context *ctx, int ret,
			       const char **key_r, const char **value_r)
{
	struct db_dict *dict = (struct db_dict *)ctx->ctx.dict;

	if (ret == DB_NOTFOUND)
		return 0;
	else if (ret != 0)
		return -1;
	
	p_clear(ctx->pool);
	*key_r = p_strndup(ctx->pool, ctx->pkey.data, ctx->pkey.size);

	switch (dict->value_type) {
	case DICT_DATA_TYPE_UINT32:
		i_assert(ctx->pdata.size == sizeof(uint32_t));
		*value_r = p_strdup(ctx->pool,
				    dec2str(*((uint32_t *)ctx->pdata.data)));
		break;
	case DICT_DATA_TYPE_STRING:
		*value_r = p_strndup(ctx->pool,
				     ctx->pdata.data, ctx->pdata.size);
		break;
	}
	return 1;
}

static int db_dict_lookup(struct dict *_dict, pool_t pool,
			  const char *key, const char **value_r)
{
	struct db_dict *dict = (struct db_dict *)_dict;
	DBT pkey, pdata;
	int ret;

	memset(&pkey, 0, sizeof(DBT));
	memset(&pdata, 0, sizeof(DBT));

	pkey.data = (char *)key;
	pkey.size = strlen(key);

	ret = dict->pdb->get(dict->pdb, NULL, &pkey, &pdata, 0);
	if (ret == DB_NOTFOUND)
		return 0;
	else if (ret != 0)
		return -1;

	switch (dict->value_type) {
	case DICT_DATA_TYPE_UINT32:
		i_assert(pdata.size == sizeof(uint32_t));
		*value_r = p_strdup(pool, dec2str(*((uint32_t *)pdata.data)));
		break;
	case DICT_DATA_TYPE_STRING:
		*value_r = p_strndup(pool, pdata.data, pdata.size);
		break;
	}
	return 1;
}

static int db_dict_iterate_next(struct db_dict_iterate_context *ctx,
				const char **key_r, const char **value_r)
{
	DBT pkey, pdata, skey;
	int ret;

	memset(&pkey, 0, sizeof(pkey));
	memset(&pdata, 0, sizeof(pdata));
	memset(&skey, 0, sizeof(skey));

	if ((ctx->flags & DICT_ITERATE_FLAG_SORT_BY_VALUE) != 0) {
		while ((ret = ctx->cursor->c_pget(ctx->cursor, &skey,
						  &ctx->pkey, &ctx->pdata,
						  DB_NEXT)) == 0) {
			/* make sure the path matches */
			if (ctx->path == NULL ||
			    strncmp(ctx->path, ctx->pkey.data,
				    ctx->pkey.size) == 0)
				break;
		}
	} else {
		ret = ctx->cursor->c_get(ctx->cursor, &ctx->pkey, &ctx->pdata,
					 DB_NEXT);
		if (ctx->path != NULL && ret == 0 &&
		    strncmp(ctx->path, ctx->pkey.data, ctx->pkey.size) != 0) {
			/* there are no more matches */
			return 0;
		}
	}

	return db_dict_iterate_set(ctx, ret, key_r, value_r);
}

static int db_dict_iterate_first(struct db_dict_iterate_context *ctx,
				 const char **key_r, const char **value_r)
{
	struct db_dict *dict = (struct db_dict *)ctx->ctx.dict;
	int ret;

	ctx->iterate_next = db_dict_iterate_next;

	if ((ctx->flags & DICT_ITERATE_FLAG_SORT_BY_VALUE) != 0) {
		/* iterating through secondary database returns values sorted */
		ret = dict->sdb->cursor(dict->sdb, NULL, &ctx->cursor, 0);
	} else {
		ret = dict->pdb->cursor(dict->pdb, NULL, &ctx->cursor, 0);
		if (ret == 0 && ctx->path != NULL) {
			ctx->pkey.data = ctx->path;
			ctx->pkey.size = strlen(ctx->path);

			ret = ctx->cursor->c_get(ctx->cursor, &ctx->pkey,
						 &ctx->pdata, DB_SET_RANGE);
			if (ret == 0 && strncmp(ctx->path, ctx->pkey.data,
						ctx->pkey.size) != 0)
				return 0;
			return db_dict_iterate_set(ctx, ret, key_r, value_r);
		}
	}
	return db_dict_iterate_next(ctx, key_r, value_r);
}

static struct dict_iterate_context *
db_dict_iterate_init(struct dict *_dict, const char *path,
		     enum dict_iterate_flags flags)
{
        struct db_dict_iterate_context *ctx;

	ctx = i_new(struct db_dict_iterate_context, 1);
	ctx->pool = pool_alloconly_create("db iter", 1024);
	ctx->cursor = NULL;
	ctx->ctx.dict = _dict;
	ctx->flags = flags;
	ctx->path = i_strdup_empty(path);
	
	ctx->iterate_next = db_dict_iterate_first;
	return &ctx->ctx;
}

static int db_dict_iterate(struct dict_iterate_context *_ctx,
			   const char **key_r, const char **value_r)
{
	struct db_dict_iterate_context *ctx =
		(struct db_dict_iterate_context *)_ctx;

	return ctx->iterate_next(ctx, key_r, value_r);
}

static void db_dict_iterate_deinit(struct dict_iterate_context *_ctx)
{
	struct db_dict_iterate_context *ctx =
		(struct db_dict_iterate_context *)_ctx;

	ctx->cursor->c_close(ctx->cursor);
	pool_unref(ctx->pool);
	i_free(ctx->path);
	i_free(ctx);
}

static struct dict_transaction_context *
db_dict_transaction_init(struct dict *_dict)
{
	struct db_dict *dict = (struct db_dict *)_dict;
	struct db_dict_transaction_context *ctx;

	ctx = i_new(struct db_dict_transaction_context, 1);
	ctx->ctx.dict = _dict;
	dict->db_env->txn_begin(dict->db_env, NULL, &ctx->tid, 0);

	return &ctx->ctx;
}

static int db_dict_transaction_commit(struct dict_transaction_context *_ctx)
{
	struct db_dict_transaction_context *ctx =
		(struct db_dict_transaction_context *)_ctx;
	int ret;

	ret = ctx->tid->commit(ctx->tid, 0);
	i_free(ctx);
	return ret == 0 ? 0 : -1;
}

static void db_dict_transaction_rollback(struct dict_transaction_context *_ctx)
{
	struct db_dict_transaction_context *ctx =
		(struct db_dict_transaction_context *)_ctx;

	ctx->tid->discard(ctx->tid, 0);
	i_free(ctx);
}

static void db_dict_set(struct dict_transaction_context *_ctx,
			const char *key, const char *value)
{
	struct db_dict_transaction_context *ctx =
		(struct db_dict_transaction_context *)_ctx;
	struct db_dict *dict = (struct db_dict *)_ctx->dict;
	DBT dkey, ddata;

	memset(&dkey, 0, sizeof(dkey));
	memset(&ddata, 0, sizeof(ddata));

	dkey.data = (char *)key;
	dkey.size = strlen(key);

	if (dict->value_type == DICT_DATA_TYPE_UINT32) {
		uint32_t ivalue = (uint32_t)strtoul(value, NULL, 10);

		ddata.data = &ivalue;
		ddata.size = sizeof(ivalue);
	} else {
		ddata.data = (char *)value;
		ddata.size = strlen(value);
	}

	dict->pdb->put(dict->pdb, ctx->tid, &dkey, &ddata, 0);
}

static void db_dict_unset(struct dict_transaction_context *_ctx,
			  const char *key)
{
	struct db_dict_transaction_context *ctx =
		(struct db_dict_transaction_context *)_ctx;
	struct db_dict *dict = (struct db_dict *)_ctx->dict;
	DBT dkey;

	memset(&dkey, 0, sizeof(dkey));
	dkey.data = (char *)key;
	dkey.size = strlen(key);
	
	dict->pdb->del(dict->pdb, ctx->tid, &dkey, 0);
}

static void db_dict_atomic_inc(struct dict_transaction_context *_ctx,
			       const char *key, long long diff)
{
	/* FIXME */
}

static struct dict dict_db_class = {
	MEMBER(name) "db",
	{
		db_dict_init,
		db_dict_deinit,
		db_dict_lookup,
		db_dict_iterate_init,
		db_dict_iterate,
		db_dict_iterate_deinit,
		db_dict_transaction_init,
		db_dict_transaction_commit,
		db_dict_transaction_rollback,
		db_dict_set,
		db_dict_unset,
		db_dict_atomic_inc
	}
};

void dict_db_register(void)
{
	dict_class_register(&dict_db_class);
}

void dict_db_unregister(void)
{
	dict_class_unregister(&dict_db_class);
}

Index: dict-private.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-dict/dict-private.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- dict-private.h	30 Jul 2006 18:06:09 -0000	1.5
+++ dict-private.h	30 Jul 2006 18:49:38 -0000	1.6
@@ -5,6 +5,7 @@
 
 struct dict_vfuncs {
 	struct dict *(*init)(struct dict *dict_class, const char *uri,
+			     enum dict_data_type value_type,
 			     const char *username);
 	void (*deinit)(struct dict *dict);
 
@@ -13,7 +14,7 @@
 
 	struct dict_iterate_context *
 		(*iterate_init)(struct dict *dict, const char *path,
-				bool recurse);
+				enum dict_iterate_flags flags);
 	int (*iterate)(struct dict_iterate_context *ctx,
 		       const char **key_r, const char **value_r);
 	void (*iterate_deinit)(struct dict_iterate_context *ctx);
@@ -24,6 +25,8 @@
 
 	void (*set)(struct dict_transaction_context *ctx,
 		    const char *key, const char *value);
+	void (*unset)(struct dict_transaction_context *ctx,
+		      const char *key);
 	void (*atomic_inc)(struct dict_transaction_context *ctx,
 			   const char *key, long long diff);
 };

Index: dict-sql.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-dict/dict-sql.c,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -d -r1.11 -r1.12
--- dict-sql.c	30 Jul 2006 18:06:09 -0000	1.11
+++ dict-sql.c	30 Jul 2006 18:49:38 -0000	1.12
@@ -101,8 +101,10 @@
 	return 0;
 }
 
-static struct dict *sql_dict_init(struct dict *dict_class, const char *uri,
-				  const char *username)
+static struct dict *
+sql_dict_init(struct dict *dict_class, const char *uri,
+	      enum dict_data_type value_type __attr_unused__,
+	      const char *username)
 {
 	struct sql_dict *dict;
 	pool_t pool;
@@ -193,7 +195,8 @@
 }
 
 static struct dict_iterate_context *
-sql_dict_iterate_init(struct dict *_dict, const char *path, bool recurse)
+sql_dict_iterate_init(struct dict *_dict, const char *path, 
+		      enum dict_iterate_flags flags)
 {
 	struct sql_dict *dict = (struct sql_dict *)_dict;
         struct sql_dict_iterate_context *ctx;
@@ -219,11 +222,15 @@
 				    sql_escape_string(dict->db,
 						      dict->username));
 		}
-		if (!recurse) {
+		if ((flags & DICT_ITERATE_FLAG_RECURSE) == 0) {
 			str_printfa(query, " AND %s NOT LIKE '%s/%%/%%'",
 				    dict->where_field,
 				    sql_escape_string(dict->db, path));
 		}
+		if ((flags & DICT_ITERATE_FLAG_SORT_BY_KEY) != 0)
+			str_printfa(query, " ORDER BY %s", dict->where_field);
+		else if ((flags & DICT_ITERATE_FLAG_SORT_BY_VALUE) != 0)
+			str_printfa(query, " ORDER BY %s", dict->select_field);
 		ctx->result = sql_query_s(dict->db, str_c(query));
 		t_pop();
 	}
@@ -344,6 +351,39 @@
 	t_pop();
 }
 
+static void sql_dict_unset(struct dict_transaction_context *_ctx,
+			   const char *key)
+{
+	struct sql_dict_transaction_context *ctx =
+		(struct sql_dict_transaction_context *)_ctx;
+	struct sql_dict *dict = (struct sql_dict *)_ctx->dict;
+	const char *query;
+	bool priv;
+
+	if (sql_path_fix(&key, &priv) < 0) {
+		i_error("sql dict: Invalid key: %s", key);
+		ctx->failed = TRUE;
+		return;
+	}
+
+	t_push();
+	if (priv) {
+		query = t_strdup_printf(
+			"DELETE FROM %s WHERE %s = '%s' AND %s = '%s'",
+			dict->table, dict->where_field,
+			sql_escape_string(dict->db, key),
+			dict->username_field,
+			sql_escape_string(dict->db, dict->username));
+	} else {
+		query = t_strdup_printf(
+			"DELETE FROM %s WHERE %s = '%s'",
+			dict->table, dict->where_field,
+			sql_escape_string(dict->db, key));
+	}
+	sql_update(ctx->sql_ctx, query);
+	t_pop();
+}
+
 static void sql_dict_atomic_inc(struct dict_transaction_context *_ctx,
 				const char *key, long long diff)
 {
@@ -395,6 +435,7 @@
 		sql_dict_transaction_commit,
 		sql_dict_transaction_rollback,
 		sql_dict_set,
+		sql_dict_unset,
 		sql_dict_atomic_inc
 	}
 };

Index: dict.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-dict/dict.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- dict.c	30 Jul 2006 18:06:09 -0000	1.9
+++ dict.c	30 Jul 2006 18:49:38 -0000	1.10
@@ -51,7 +51,8 @@
 		array_free(&dict_classes);
 }
 
-struct dict *dict_init(const char *uri, const char *username)
+struct dict *dict_init(const char *uri, enum dict_data_type value_type,
+		       const char *username)
 {
 	struct dict *dict;
 	const char *p, *name;
@@ -72,7 +73,7 @@
 	}
 	t_pop();
 
-	return dict->v.init(dict, p+1, username);
+	return dict->v.init(dict, p+1, value_type, username);
 }
 
 void dict_deinit(struct dict **_dict)
@@ -90,9 +91,10 @@
 }
 
 struct dict_iterate_context *
-dict_iterate_init(struct dict *dict, const char *path, bool recurse)
+dict_iterate_init(struct dict *dict, const char *path, 
+		  enum dict_iterate_flags flags)
 {
-	return dict->v.iterate_init(dict, path, recurse);
+	return dict->v.iterate_init(dict, path, flags);
 }
 
 int dict_iterate(struct dict_iterate_context *ctx,
@@ -128,6 +130,13 @@
 	ctx->changed = TRUE;
 }
 
+void dict_unset(struct dict_transaction_context *ctx,
+		const char *key)
+{
+	ctx->dict->v.unset(ctx, key);
+	ctx->changed = TRUE;
+}
+
 void dict_atomic_inc(struct dict_transaction_context *ctx,
 		     const char *key, long long diff)
 {

Index: dict.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-dict/dict.h,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- dict.h	31 Jan 2006 06:05:22 -0000	1.6
+++ dict.h	30 Jul 2006 18:49:38 -0000	1.7
@@ -6,12 +6,24 @@
 
 struct dict;
 
+enum dict_iterate_flags {
+	DICT_ITERATE_FLAG_RECURSE             = 0x01,
+	DICT_ITERATE_FLAG_SORT_BY_KEY         = 0x02,
+	DICT_ITERATE_FLAG_SORT_BY_VALUE       = 0x04
+};
+
+enum dict_data_type {
+	DICT_DATA_TYPE_STRING,
+	DICT_DATA_TYPE_UINT32
+};
+
 void dict_class_register(struct dict *dict_class);
 void dict_class_unregister(struct dict *dict_class);
 
 /* Open dictionary with given URI (type:data).
    If URI is invalid, returns NULL. */
-struct dict *dict_init(const char *uri, const char *username);
+struct dict *dict_init(const char *uri, enum dict_data_type value_type,
+		       const char *username);
 /* Close dictionary. */
 void dict_deinit(struct dict **dict);
 
@@ -20,10 +32,11 @@
 int dict_lookup(struct dict *dict, pool_t pool,
 		const char *key, const char **value_r);
 
-/* Iterate through all values in a path. If recurse is FALSE, keys in
-   the given path are returned, but not their children. */
+/* Iterate through all values in a path. flag indicates how iteration
+   is carried out */
 struct dict_iterate_context *
-dict_iterate_init(struct dict *dict, const char *path, bool recurse);
+dict_iterate_init(struct dict *dict, const char *path, 
+		  enum dict_iterate_flags flags);
 /* Returns -1 = error, 0 = finished, 1 = key/value set */
 int dict_iterate(struct dict_iterate_context *ctx,
 		 const char **key_r, const char **value_r);
@@ -39,6 +52,9 @@
 /* Set key=value in dictionary. */
 void dict_set(struct dict_transaction_context *ctx,
 	      const char *key, const char *value);
+/* Unset a record in dictionary, identified by key*/
+void dict_unset(struct dict_transaction_context *ctx,
+		const char *key);
 /* Increase/decrease a numeric value in dictionary. Note that the value is
    changed when transaction is being committed, so you can't know beforehand
    what the value will become. */



More information about the dovecot-cvs mailing list