}
args = t_strsplit(line, "\t");
- if (str_array_length(args) != 2) {
+ if (str_array_length(args) < 2) {
i_error("dict client: ITERATE: broken input");
return -1;
}
/* <flags> <path> */
- conn->iter_ctx = dict_iterate_init(conn->dict, args[1], atoi(args[0]));
+ conn->iter_ctx = dict_iterate_init_multiple(conn->dict, args+1,
+ atoi(args[0]));
o_stream_set_flush_callback(conn->output, cmd_iterate_flush, conn);
cmd_iterate_flush(conn);
}
static struct dict_iterate_context *
-client_dict_iterate_init(struct dict *_dict, const char *path,
+client_dict_iterate_init(struct dict *_dict, const char *const *paths,
enum dict_iterate_flags flags)
{
struct client_dict *dict = (struct client_dict *)_dict;
ctx->pool = pool_alloconly_create("client dict iteration", 512);
T_BEGIN {
- const char *query;
+ string_t *query = t_str_new(256);
+ unsigned int i;
- query = t_strdup_printf("%c%d\t%s\n", DICT_PROTOCOL_CMD_ITERATE,
- flags, dict_client_escape(path));
- if (client_dict_send_query(dict, query) < 0)
+ str_printfa(query, "%c%d", DICT_PROTOCOL_CMD_ITERATE, flags);
+ for (i = 0; paths[i] != NULL; i++) {
+ str_append_c(query, '\t');
+ str_append(query, dict_client_escape(paths[i]));
+ }
+ str_append_c(query, '\n');
+ if (client_dict_send_query(dict, str_c(query)) < 0)
ctx->failed = TRUE;
} T_END;
return &ctx->ctx;
int fd;
};
+struct file_dict_iterate_path {
+ const char *path;
+ unsigned int len;
+};
+
struct file_dict_iterate_context {
struct dict_iterate_context ctx;
+ pool_t pool;
struct hash_iterate_context *iter;
- char *path;
- unsigned int path_len;
+ struct file_dict_iterate_path *paths;
enum dict_iterate_flags flags;
unsigned int failed:1;
}
static struct dict_iterate_context *
-file_dict_iterate_init(struct dict *_dict, const char *path,
+file_dict_iterate_init(struct dict *_dict, const char *const *paths,
enum dict_iterate_flags flags)
{
struct file_dict_iterate_context *ctx;
struct file_dict *dict = (struct file_dict *)_dict;
+ unsigned int i, path_count;
+ pool_t pool;
- ctx = i_new(struct file_dict_iterate_context, 1);
+ pool = pool_alloconly_create("file dict iterate", 256);
+ ctx = p_new(pool, struct file_dict_iterate_context, 1);
ctx->ctx.dict = _dict;
- ctx->path = i_strdup(path);
- ctx->path_len = strlen(path);
+ ctx->pool = pool;
+
+ for (path_count = 0; paths[path_count] != NULL; path_count++) ;
+ ctx->paths = p_new(pool, struct file_dict_iterate_path, path_count + 1);
+ for (i = 0; i < path_count; i++) {
+ ctx->paths[i].path = p_strdup(pool, paths[i]);
+ ctx->paths[i].len = strlen(paths[i]);
+ }
ctx->flags = flags;
ctx->iter = hash_table_iterate_init(dict->hash);
return &ctx->ctx;
}
+static const struct file_dict_iterate_path *
+file_dict_iterate_find_path(struct file_dict_iterate_context *ctx,
+ const char *key)
+{
+ unsigned int i;
+
+ for (i = 0; ctx->paths[i].path != NULL; i++) {
+ if (strncmp(ctx->paths[i].path, key, ctx->paths[i].len) == 0)
+ return &ctx->paths[i];
+ }
+ return NULL;
+}
+
static bool file_dict_iterate(struct dict_iterate_context *_ctx,
const char **key_r, const char **value_r)
{
struct file_dict_iterate_context *ctx =
(struct file_dict_iterate_context *)_ctx;
+ const struct file_dict_iterate_path *path;
void *key, *value;
while (hash_table_iterate(ctx->iter, &key, &value)) {
- if (strncmp(ctx->path, key, ctx->path_len) != 0)
+ path = file_dict_iterate_find_path(ctx, key);
+ if (path == NULL)
continue;
if ((ctx->flags & DICT_ITERATE_FLAG_RECURSE) == 0 &&
- strchr((char *)key + ctx->path_len, '/') != NULL)
+ strchr((char *)key + path->len, '/') != NULL)
continue;
*key_r = key;
int ret = ctx->failed ? -1 : 0;
hash_table_iterate_deinit(&ctx->iter);
- i_free(ctx->path);
- i_free(ctx);
+ pool_unref(&ctx->pool);
return ret;
}
const char *key, const char **value_r);
struct dict_iterate_context *
- (*iterate_init)(struct dict *dict, const char *path,
+ (*iterate_init)(struct dict *dict, const char *const *paths,
enum dict_iterate_flags flags);
bool (*iterate)(struct dict_iterate_context *ctx,
const char **key_r, const char **value_r);
struct sql_dict_iterate_context {
struct dict_iterate_context ctx;
+ pool_t pool;
+
enum dict_iterate_flags flags;
- char *path;
+ const char **paths;
struct sql_result *result;
string_t *key;
const struct dict_sql_map *map;
unsigned int key_prefix_len, pattern_prefix_len, next_map_idx;
+ unsigned int path_idx;
bool failed;
};
t_array_init(values, dict->set->max_field_count);
maps = array_get(&dict->set->maps, &count);
for (i = ctx->next_map_idx; i < count; i++) {
- if (dict_sql_map_match(&maps[i], ctx->path,
+ if (dict_sql_map_match(&maps[i], ctx->paths[ctx->path_idx],
values, &pat_len, &path_len, TRUE) &&
((ctx->flags & DICT_ITERATE_FLAG_RECURSE) != 0 ||
array_count(values)+1 >= array_count(&maps[i].sql_fields))) {
ctx->key_prefix_len = path_len;
ctx->pattern_prefix_len = pat_len;
ctx->next_map_idx = i + 1;
+
+ str_truncate(ctx->key, 0);
+ str_append(ctx->key, ctx->paths[ctx->path_idx]);
return &maps[i];
}
}
+
+ /* try the next path, if there is any */
+ ctx->path_idx++;
+ if (ctx->paths[ctx->path_idx] != NULL)
+ return sql_dict_iterate_find_next_map(ctx, values);
return NULL;
}
recurse_type = (ctx->flags & DICT_ITERATE_FLAG_RECURSE) == 0 ?
SQL_DICT_RECURSE_ONE : SQL_DICT_RECURSE_FULL;
- sql_dict_where_build(dict, map, &values, ctx->path[0],
+ sql_dict_where_build(dict, map, &values,
+ ctx->paths[ctx->path_idx][0],
recurse_type, query);
if ((ctx->flags & DICT_ITERATE_FLAG_SORT_BY_KEY) != 0) {
}
static struct dict_iterate_context *
-sql_dict_iterate_init(struct dict *_dict, const char *path,
+sql_dict_iterate_init(struct dict *_dict, const char *const *paths,
enum dict_iterate_flags flags)
{
struct sql_dict_iterate_context *ctx;
+ unsigned int i, path_count;
+ pool_t pool;
- ctx = i_new(struct sql_dict_iterate_context, 1);
+ pool = pool_alloconly_create("sql dict iterate", 512);
+ ctx = p_new(pool, struct sql_dict_iterate_context, 1);
ctx->ctx.dict = _dict;
- ctx->path = i_strdup(path);
+ ctx->pool = pool;
ctx->flags = flags;
- ctx->key = str_new(default_pool, 256);
- str_append(ctx->key, ctx->path);
+ for (path_count = 0; paths[path_count] != NULL; path_count++) ;
+ ctx->paths = p_new(pool, const char *, path_count + 1);
+ for (i = 0; i < path_count; i++)
+ ctx->paths[i] = p_strdup(pool, paths[i]);
+
+ ctx->key = str_new(pool, 256);
if (!sql_dict_iterate_next_query(ctx)) {
- i_error("sql dict iterate: Invalid/unmapped path: %s", path);
+ i_error("sql dict iterate: Invalid/unmapped path: %s",
+ paths[0]);
ctx->result = NULL;
return &ctx->ctx;
}
if (ctx->result != NULL)
sql_result_unref(ctx->result);
- str_free(&ctx->key);
- i_free(ctx->path);
- i_free(ctx);
+ pool_unref(&ctx->pool);
return ret;
}
dict_iterate_init(struct dict *dict, const char *path,
enum dict_iterate_flags flags)
{
- i_assert(dict_key_prefix_is_valid(path));
- return dict->v.iterate_init(dict, path, flags);
+ const char *paths[2];
+
+ paths[0] = path;
+ paths[1] = NULL;
+ return dict_iterate_init_multiple(dict, paths, flags);
+}
+
+struct dict_iterate_context *
+dict_iterate_init_multiple(struct dict *dict, const char *const *paths,
+ enum dict_iterate_flags flags)
+{
+ unsigned int i;
+
+ i_assert(paths[0] != NULL);
+ for (i = 0; paths[i] != NULL; i++)
+ i_assert(dict_key_prefix_is_valid(paths[i]));
+ return dict->v.iterate_init(dict, paths, flags);
}
bool dict_iterate(struct dict_iterate_context *ctx,
struct dict_iterate_context *
dict_iterate_init(struct dict *dict, const char *path,
enum dict_iterate_flags flags);
+struct dict_iterate_context *
+dict_iterate_init_multiple(struct dict *dict, const char *const *paths,
+ enum dict_iterate_flags flags);
bool dict_iterate(struct dict_iterate_context *ctx,
const char **key_r, const char **value_r);
/* Returns 0 = ok, -1 = iteration failed */