[dovecot-cvs]
dovecot/src/lib-dict .cvsignore, NONE, 1.1 Makefile.am,
NONE, 1.1 dict-private.h, NONE, 1.1 dict-sql.c, NONE,
1.1 dict-sql.h, NONE, 1.1 dict.c, NONE, 1.1 dict.h, NONE, 1.1
cras at dovecot.org
cras at dovecot.org
Sat Dec 10 20:59:05 EET 2005
Update of /var/lib/cvs/dovecot/src/lib-dict
In directory talvi:/tmp/cvs-serv30625/src/lib-dict
Added Files:
.cvsignore Makefile.am dict-private.h dict-sql.c dict-sql.h
dict.c dict.h
Log Message:
Added dictionary API and implementation for SQL. It's meant for looking and
modifying key=value pairs. In future we may need to use this for many
different things, but for now it's only used by quota-dict plugin.
--- NEW FILE: .cvsignore ---
*.la
*.lo
*.o
.deps
.libs
Makefile
Makefile.in
so_locations
--- NEW FILE: Makefile.am ---
noinst_LIBRARIES = libdict.a
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-sql \
$(SQL_CFLAGS)
libdict_a_SOURCES = \
dict.c \
dict-sql.c
noinst_HEADERS = \
dict.h \
dict-private.h
--- NEW FILE: dict-private.h ---
#ifndef __DICT_PRIVATE_H
#define __DICT_PRIVATE_H
#include "dict.h"
struct dict_vfuncs {
struct dict *(*init)(struct dict *dict_class, const char *uri);
void (*deinit)(struct dict *dict);
char *(*lookup)(struct dict *dict, pool_t pool, const char *key);
struct dict_iterate_context *
(*iterate_init)(struct dict *dict, const char *path,
int recurse);
int (*iterate)(struct dict_iterate_context *ctx,
const char **key_r, const char **value_r);
void (*iterate_deinit)(struct dict_iterate_context *ctx);
struct dict_transaction_context *(*transaction_init)(struct dict *dict);
int (*transaction_commit)(struct dict_transaction_context *ctx);
void (*transaction_rollback)(struct dict_transaction_context *ctx);
void (*set)(struct dict_transaction_context *ctx,
const char *key, const char *value);
void (*atomic_inc)(struct dict_transaction_context *ctx,
const char *key, long long diff);
};
struct dict {
const char *name;
struct dict_vfuncs v;
};
struct dict_iterate_context {
struct dict *dict;
};
struct dict_transaction_context {
struct dict *dict;
};
#endif
--- NEW FILE: dict-sql.c ---
/* Copyright (C) 2005 Timo Sirainen */
#include "lib.h"
#include "istream.h"
#include "str.h"
#include "strescape.h"
#include "sql-api-private.h"
#include "dict-private.h"
#include "dict-sql.h"
#include <unistd.h>
#include <fcntl.h>
struct sql_dict {
struct dict dict;
pool_t pool;
struct sql_db *db;
const char *connect_string;
const char *table, *select_field, *where_field;
};
struct sql_dict_iterate_context {
struct dict_iterate_context ctx;
struct sql_result *result;
};
static int sql_dict_read_config(struct sql_dict *dict, const char *path)
{
struct istream *input;
const char *line, *value;
int fd;
fd = open(path, O_RDONLY);
if (fd == -1) {
i_error("open(%s) failed: %m", path);
return -1;
}
input = i_stream_create_file(fd, default_pool, (size_t)-1, FALSE);
while ((line = i_stream_read_next_line(input)) != NULL) {
value = strchr(line, '=');
if (value == NULL)
continue;
t_push();
line = t_strdup_until(line, value);
value++;
if (strcmp(line, "connect") == 0)
dict->connect_string = p_strdup(dict->pool, value);
else if (strcmp(line, "table") == 0)
dict->table = p_strdup(dict->pool, value);
else if (strcmp(line, "select_field") == 0)
dict->select_field = p_strdup(dict->pool, value);
else if (strcmp(line, "where_field") == 0)
dict->where_field = p_strdup(dict->pool, value);
t_pop();
}
i_stream_unref(input);
(void)close(fd);
return 0;
}
static struct dict *sql_dict_init(struct dict *dict_class, const char *uri)
{
struct sql_dict *dict;
pool_t pool;
pool = pool_alloconly_create("sql dict", 1024);
dict = p_new(pool, struct sql_dict, 1);
dict->pool = pool;
dict->dict = *dict_class;
if (sql_dict_read_config(dict, uri) <= 0) {
pool_unref(pool);
return NULL;
}
t_push();
dict->db = sql_init(dict_class->name, dict->connect_string);
t_pop();
return &dict->dict;
}
static void sql_dict_deinit(struct dict *_dict)
{
struct sql_dict *dict = (struct sql_dict *)_dict;
sql_deinit(dict->db);
}
static char *sql_dict_lookup(struct dict *_dict, pool_t pool, const char *key)
{
struct sql_dict *dict = (struct sql_dict *)_dict;
struct sql_result *result;
const char *query;
char *ret;
t_push();
query = t_strdup_printf("SELECT %s FROM %s WHERE %s = '%s'",
dict->select_field, dict->table,
dict->where_field, str_escape(key));
result = sql_query_s(dict->db, query);
t_pop();
if (sql_result_next_row(result) <= 0)
ret = NULL;
else
ret = p_strdup(pool, sql_result_get_field_value(result, 0));
sql_result_free(result);
return ret;
}
static struct dict_iterate_context *
sql_dict_iterate_init(struct dict *_dict, const char *path, int recurse)
{
struct sql_dict *dict = (struct sql_dict *)_dict;
struct sql_dict_iterate_context *ctx;
string_t *query;
ctx = i_new(struct sql_dict_iterate_context, 1);
ctx->ctx.dict = _dict;
t_push();
query = t_str_new(256);
str_printfa(query, "SELECT %s, %s FROM %s WHERE %s LIKE '%s/%%'",
dict->where_field, dict->select_field,
dict->table, dict->where_field, str_escape(path));
if (!recurse) {
str_printfa(query, " AND %s NOT LIKE '%s/%%/%%'",
dict->where_field, str_escape(path));
}
ctx->result = sql_query_s(dict->db, str_c(query));
t_pop();
return &ctx->ctx;
}
static int sql_dict_iterate(struct dict_iterate_context *_ctx,
const char **key_r, const char **value_r)
{
struct sql_dict_iterate_context *ctx =
(struct sql_dict_iterate_context *)_ctx;
int ret;
if ((ret = sql_result_next_row(ctx->result)) <= 0)
return ret;
*key_r = sql_result_get_field_value(ctx->result, 0);
*value_r = sql_result_get_field_value(ctx->result, 1);
return 1;
}
static void sql_dict_iterate_deinit(struct dict_iterate_context *_ctx)
{
struct sql_dict_iterate_context *ctx =
(struct sql_dict_iterate_context *)_ctx;
sql_result_free(ctx->result);
}
struct sql_dict_transaction_context {
struct dict_transaction_context ctx;
struct sql_transaction_context *sql_ctx;
};
static struct dict_transaction_context *
sql_dict_transaction_init(struct dict *_dict)
{
struct sql_dict *dict = (struct sql_dict *)_dict;
struct sql_dict_transaction_context *ctx;
ctx = i_new(struct sql_dict_transaction_context, 1);
ctx->ctx.dict = _dict;
ctx->sql_ctx = sql_transaction_begin(dict->db);
return &ctx->ctx;
}
static int sql_dict_transaction_commit(struct dict_transaction_context *_ctx)
{
struct sql_dict_transaction_context *ctx =
(struct sql_dict_transaction_context *)_ctx;
const char *error;
int ret;
ret = sql_transaction_commit_s(ctx->sql_ctx, &error);
if (ret < 0)
i_error("sql dict: commit failed: %s", error);
i_free(ctx);
return ret;
}
static void sql_dict_transaction_rollback(struct dict_transaction_context *_ctx)
{
struct sql_dict_transaction_context *ctx =
(struct sql_dict_transaction_context *)_ctx;
sql_transaction_rollback(ctx->sql_ctx);
i_free(ctx);
}
static void sql_dict_set(struct dict_transaction_context *_ctx,
const char *key, const char *value)
{
struct sql_dict_transaction_context *ctx =
(struct sql_dict_transaction_context *)_ctx;
struct sql_dict *dict = (struct sql_dict *)_ctx->dict;
const char *query;
t_push();
query = t_strdup_printf("UPDATE %s SET %s = '%s' WHERE %s = '%s'",
dict->table, dict->select_field, str_escape(value),
dict->where_field, str_escape(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)
{
struct sql_dict_transaction_context *ctx =
(struct sql_dict_transaction_context *)_ctx;
struct sql_dict *dict = (struct sql_dict *)_ctx->dict;
const char *query;
t_push();
query = t_strdup_printf("UPDATE %s SET %s = %s + %lld WHERE %s = '%s'",
dict->table, dict->select_field,
dict->select_field, diff,
dict->where_field, str_escape(key));
sql_update(ctx->sql_ctx, query);
t_pop();
}
static struct dict sql_dict = {
MEMBER(name) "sql",
{
sql_dict_init,
sql_dict_deinit,
sql_dict_lookup,
sql_dict_iterate_init,
sql_dict_iterate,
sql_dict_iterate_deinit,
sql_dict_transaction_init,
sql_dict_transaction_commit,
sql_dict_transaction_rollback,
sql_dict_set,
sql_dict_atomic_inc
}
};
static struct dict *dict_sql_classes;
void dict_sql_register(void)
{
int i, count;
/* @UNSAFE */
for (count = 0; sql_db_drivers[count] != NULL; count++) ;
dict_sql_classes = i_new(struct dict, count);
for (i = 0; i < count; i++) {
dict_sql_classes[i] = sql_dict;
dict_sql_classes[i].name = sql_db_drivers[i]->name;
dict_class_register(&dict_sql_classes[i]);
}
}
void dict_sql_unregister(void)
{
int i;
for (i = 0; sql_db_drivers[i] != NULL; i++)
dict_class_unregister(&dict_sql_classes[i]);
i_free(dict_sql_classes);
}
--- NEW FILE: dict-sql.h ---
#ifndef __DICT_SQL_H
#define __DICT_SQL_H
void dict_sql_register(void);
void dict_sql_unregister(void);
#endif
--- NEW FILE: dict.c ---
/* Copyright (C) 2005 Timo Sirainen */
#include "lib.h"
#include "array.h"
#include "dict-sql.h"
#include "dict-private.h"
static array_t ARRAY_DEFINE(dict_classes, struct dict *);
static int dict_count = 0;
static void dict_class_register_all(void)
{
dict_sql_register();
}
static void dict_class_unregister_all(void)
{
dict_sql_unregister();
}
static struct dict *dict_class_lookup(const char *name)
{
struct dict *const *dicts;
unsigned int i, count;
dicts = array_get(&dict_classes, &count);
for (i = 0; i < count; i++) {
if (strcmp(dicts[i]->name, name) == 0)
return dicts[i];
}
return NULL;
}
void dict_class_register(struct dict *dict_class)
{
if (!array_is_created(&dict_classes))
ARRAY_CREATE(&dict_classes, default_pool, struct dict *, 8);
if (dict_class_lookup(dict_class->name) != NULL) {
i_fatal("dict_class_register(%s): Already registered",
dict_class->name);
}
array_append(&dict_classes, &dict_class, 1);
}
void dict_class_unregister(struct dict *dict_class)
{
struct dict *const *dicts;
unsigned int i, count;
dicts = array_get(&dict_classes, &count);
for (i = 0; i < count; i++) {
if (dicts[i] == dict_class) {
array_delete(&dict_classes, i, 1);
break;
}
}
i_assert(i < count);
if (array_count(&dict_classes) == 0)
array_free(&dict_classes);
}
struct dict *dict_init(const char *uri)
{
struct dict *dict;
const char *p;
if (dict_count++ == 0)
dict_class_register_all();
p = strchr(uri, ':');
if (p == NULL) {
i_error("URI is missing ':': %s", uri);
return NULL;
}
t_push();
dict = dict_class_lookup(t_strdup_until(uri, p));
t_pop();
if (dict == NULL)
return NULL;
return dict->v.init(dict, p+1);
}
void dict_deinit(struct dict *dict)
{
dict->v.deinit(dict);
if (--dict_count == 0)
dict_class_unregister_all();
}
char *dict_lookup(struct dict *dict, pool_t pool, const char *key)
{
return dict->v.lookup(dict, pool, key);
}
struct dict_iterate_context *
dict_iterate_init(struct dict *dict, const char *path, int recurse)
{
return dict->v.iterate_init(dict, path, recurse);
}
int dict_iterate(struct dict_iterate_context *ctx,
const char **key_r, const char **value_r)
{
return ctx->dict->v.iterate(ctx, key_r, value_r);
}
void dict_iterate_deinit(struct dict_iterate_context *ctx)
{
ctx->dict->v.iterate_deinit(ctx);
}
struct dict_transaction_context *dict_transaction_begin(struct dict *dict)
{
return dict->v.transaction_init(dict);
}
int dict_transaction_commit(struct dict_transaction_context *ctx)
{
return ctx->dict->v.transaction_commit(ctx);
}
void dict_transaction_rollback(struct dict_transaction_context *ctx)
{
ctx->dict->v.transaction_rollback(ctx);
}
void dict_set(struct dict_transaction_context *ctx,
const char *key, const char *value)
{
ctx->dict->v.set(ctx, key, value);
}
void dict_atomic_inc(struct dict_transaction_context *ctx,
const char *key, long long diff)
{
ctx->dict->v.atomic_inc(ctx, key, diff);
}
--- NEW FILE: dict.h ---
#ifndef __DICT_H
#define __DICT_H
#define DICT_PATH_PRIVATE "priv/"
#define DICT_PATH_SHARED "shared/"
struct dict;
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);
/* Close dictionary. */
void dict_deinit(struct dict *dict);
/* Return value for key, or NULL if not found. */
char *dict_lookup(struct dict *dict, pool_t pool, const char *key);
/* Iterate through all values in a path. If recurse is FALSE, keys in
the given path are returned, but not their children. */
struct dict_iterate_context *
dict_iterate_init(struct dict *dict, const char *path, int recurse);
/* 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);
void dict_iterate_deinit(struct dict_iterate_context *ctx);
/* Start a new dictionary transaction. */
struct dict_transaction_context *dict_transaction_begin(struct dict *dict);
/* Commit the transaction. Returns 0 if ok, -1 if failed. */
int dict_transaction_commit(struct dict_transaction_context *ctx);
/* Rollback all changes made in transaction. */
void dict_transaction_rollback(struct dict_transaction_context *ctx);
/* Set key=value in dictionary. */
void dict_set(struct dict_transaction_context *ctx,
const char *key, const char *value);
/* 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. */
void dict_atomic_inc(struct dict_transaction_context *ctx,
const char *key, long long diff);
#endif
More information about the dovecot-cvs
mailing list