dict-sql.c (dovecot-2.3.16) | : | dict-sql.c (dovecot-2.3.17) | ||
---|---|---|---|---|
skipping to change at line 42 | skipping to change at line 42 | |||
const void *value_binary; | const void *value_binary; | |||
size_t value_binary_size; | size_t value_binary_size; | |||
}; | }; | |||
ARRAY_DEFINE_TYPE(sql_dict_param, struct sql_dict_param); | ARRAY_DEFINE_TYPE(sql_dict_param, struct sql_dict_param); | |||
struct sql_dict_iterate_context { | struct sql_dict_iterate_context { | |||
struct dict_iterate_context ctx; | struct dict_iterate_context ctx; | |||
pool_t pool; | pool_t pool; | |||
enum dict_iterate_flags flags; | enum dict_iterate_flags flags; | |||
const char **paths; | const char *path; | |||
struct sql_result *result; | struct sql_result *result; | |||
string_t *key; | string_t *key; | |||
const struct dict_sql_map *map; | const struct dict_sql_map *map; | |||
size_t key_prefix_len, pattern_prefix_len; | size_t key_prefix_len, pattern_prefix_len; | |||
unsigned int path_idx, sql_fields_start_idx, next_map_idx; | unsigned int sql_fields_start_idx, next_map_idx; | |||
bool destroyed; | bool destroyed; | |||
bool synchronous_result; | bool synchronous_result; | |||
bool iter_query_sent; | bool iter_query_sent; | |||
bool allow_null_map; /* allow next map to be NULL */ | bool allow_null_map; /* allow next map to be NULL */ | |||
const char *error; | const char *error; | |||
}; | }; | |||
struct sql_dict_inc_row { | struct sql_dict_inc_row { | |||
struct sql_dict_inc_row *prev; | struct sql_dict_inc_row *prev; | |||
unsigned int rows; | unsigned int rows; | |||
skipping to change at line 105 | skipping to change at line 105 | |||
struct dict **dict_r, const char **error_r) | struct dict **dict_r, const char **error_r) | |||
{ | { | |||
struct sql_settings sql_set; | struct sql_settings sql_set; | |||
struct sql_dict *dict; | struct sql_dict *dict; | |||
pool_t pool; | pool_t pool; | |||
pool = pool_alloconly_create("sql dict", 2048); | pool = pool_alloconly_create("sql dict", 2048); | |||
dict = p_new(pool, struct sql_dict, 1); | dict = p_new(pool, struct sql_dict, 1); | |||
dict->pool = pool; | dict->pool = pool; | |||
dict->dict = *driver; | dict->dict = *driver; | |||
dict->username = p_strdup(pool, set->username); | ||||
dict->set = dict_sql_settings_read(uri, error_r); | dict->set = dict_sql_settings_read(uri, error_r); | |||
if (dict->set == NULL) { | if (dict->set == NULL) { | |||
pool_unref(&pool); | pool_unref(&pool); | |||
return -1; | return -1; | |||
} | } | |||
i_zero(&sql_set); | i_zero(&sql_set); | |||
sql_set.driver = driver->name; | sql_set.driver = driver->name; | |||
sql_set.connect_string = dict->set->connect; | sql_set.connect_string = dict->set->connect; | |||
sql_set.event_parent = set->event_parent; | sql_set.event_parent = set->event_parent; | |||
skipping to change at line 133 | skipping to change at line 132 | |||
} | } | |||
static void sql_dict_deinit(struct dict *_dict) | static void sql_dict_deinit(struct dict *_dict) | |||
{ | { | |||
struct sql_dict *dict = (struct sql_dict *)_dict; | struct sql_dict *dict = (struct sql_dict *)_dict; | |||
sql_unref(&dict->db); | sql_unref(&dict->db); | |||
pool_unref(&dict->pool); | pool_unref(&dict->pool); | |||
} | } | |||
static void sql_dict_wait(struct dict *dict ATTR_UNUSED) | static void sql_dict_wait(struct dict *_dict) | |||
{ | { | |||
/* FIXME: lib-sql doesn't support this yet */ | struct sql_dict *dict = (struct sql_dict *)_dict; | |||
sql_wait(dict->db); | ||||
} | } | |||
/* Try to match path to map->pattern. For example pattern="shared/x/$/$/y" | /* Try to match path to map->pattern. For example pattern="shared/x/$/$/y" | |||
and path="shared/x/1/2/y", this is match and pattern_values=[1, 2]. */ | and path="shared/x/1/2/y", this is match and pattern_values=[1, 2]. */ | |||
static bool | static bool | |||
dict_sql_map_match(const struct dict_sql_map *map, const char *path, | dict_sql_map_match(const struct dict_sql_map *map, const char *path, | |||
ARRAY_TYPE(const_string) *pattern_values, size_t *pat_len_r, | ARRAY_TYPE(const_string) *pattern_values, size_t *pat_len_r, | |||
size_t *path_len_r, bool partial_ok, bool recurse) | size_t *path_len_r, bool partial_ok, bool recurse) | |||
{ | { | |||
const char *path_start = path; | const char *path_start = path; | |||
skipping to change at line 348 | skipping to change at line 348 | |||
const struct dict_sql_field *field, | const struct dict_sql_field *field, | |||
const char *value, const char *value_suffix, | const char *value, const char *value_suffix, | |||
ARRAY_TYPE(sql_dict_param) *params, | ARRAY_TYPE(sql_dict_param) *params, | |||
const char **error_r) | const char **error_r) | |||
{ | { | |||
return sql_dict_value_get(map, field->value_type, field->name, | return sql_dict_value_get(map, field->value_type, field->name, | |||
value, value_suffix, params, error_r); | value, value_suffix, params, error_r); | |||
} | } | |||
static int | static int | |||
sql_dict_where_build(struct sql_dict *dict, const struct dict_sql_map *map, | sql_dict_where_build(const char *username, const struct dict_sql_map *map, | |||
const ARRAY_TYPE(const_string) *values_arr, | const ARRAY_TYPE(const_string) *values_arr, | |||
bool add_username, enum sql_recurse_type recurse_type, | bool add_username, enum sql_recurse_type recurse_type, | |||
string_t *query, ARRAY_TYPE(sql_dict_param) *params, | string_t *query, ARRAY_TYPE(sql_dict_param) *params, | |||
const char **error_r) | const char **error_r) | |||
{ | { | |||
const struct dict_sql_field *pattern_fields; | const struct dict_sql_field *pattern_fields; | |||
const char *const *pattern_values; | const char *const *pattern_values; | |||
unsigned int i, count, count2, exact_count; | unsigned int i, count, count2, exact_count; | |||
pattern_fields = array_get(&map->pattern_fields, &count); | pattern_fields = array_get(&map->pattern_fields, &count); | |||
skipping to change at line 372 | skipping to change at line 372 | |||
i_assert(count2 <= count); | i_assert(count2 <= count); | |||
if (count2 == 0 && !add_username) { | if (count2 == 0 && !add_username) { | |||
/* we want everything */ | /* we want everything */ | |||
return 0; | return 0; | |||
} | } | |||
str_append(query, " WHERE"); | str_append(query, " WHERE"); | |||
exact_count = count == count2 && recurse_type != SQL_DICT_RECURSE_NONE ? | exact_count = count == count2 && recurse_type != SQL_DICT_RECURSE_NONE ? | |||
count2-1 : count2; | count2-1 : count2; | |||
if (exact_count != array_count(values_arr)) { | ||||
*error_r = t_strdup_printf("Key continues past the matched patter | ||||
n %s", map->pattern); | ||||
return -1; | ||||
} | ||||
for (i = 0; i < exact_count; i++) { | for (i = 0; i < exact_count; i++) { | |||
if (i > 0) | if (i > 0) | |||
str_append(query, " AND"); | str_append(query, " AND"); | |||
str_printfa(query, " %s = ?", pattern_fields[i].name); | str_printfa(query, " %s = ?", pattern_fields[i].name); | |||
if (sql_dict_field_get_value(map, &pattern_fields[i], | if (sql_dict_field_get_value(map, &pattern_fields[i], | |||
pattern_values[i], "", | pattern_values[i], "", | |||
params, error_r) < 0) | params, error_r) < 0) | |||
return -1; | return -1; | |||
} | } | |||
switch (recurse_type) { | switch (recurse_type) { | |||
skipping to change at line 424 | skipping to change at line 429 | |||
return -1; | return -1; | |||
} | } | |||
break; | break; | |||
} | } | |||
if (add_username) { | if (add_username) { | |||
struct sql_dict_param *param = array_append_space(params); | struct sql_dict_param *param = array_append_space(params); | |||
if (count2 > 0) | if (count2 > 0) | |||
str_append(query, " AND"); | str_append(query, " AND"); | |||
str_printfa(query, " %s = ?", map->username_field); | str_printfa(query, " %s = ?", map->username_field); | |||
param->value_type = DICT_SQL_TYPE_STRING; | param->value_type = DICT_SQL_TYPE_STRING; | |||
param->value_str = dict->username; | param->value_str = t_strdup(username); | |||
} | } | |||
return 0; | return 0; | |||
} | } | |||
static int | static int | |||
sql_lookup_get_query(struct sql_dict *dict, const char *key, | sql_lookup_get_query(struct sql_dict *dict, | |||
const struct dict_op_settings *set, | ||||
const char *key, | ||||
const struct dict_sql_map **map_r, | const struct dict_sql_map **map_r, | |||
struct sql_statement **stmt_r, | struct sql_statement **stmt_r, | |||
const char **error_r) | const char **error_r) | |||
{ | { | |||
const struct dict_sql_map *map; | const struct dict_sql_map *map; | |||
ARRAY_TYPE(const_string) pattern_values; | ARRAY_TYPE(const_string) pattern_values; | |||
const char *error; | const char *error; | |||
map = *map_r = sql_dict_find_map(dict, key, &pattern_values); | map = *map_r = sql_dict_find_map(dict, key, &pattern_values); | |||
if (map == NULL) { | if (map == NULL) { | |||
*error_r = t_strdup_printf( | *error_r = t_strdup_printf( | |||
"sql dict lookup: Invalid/unmapped key: %s", key); | "sql dict lookup: Invalid/unmapped key: %s", key); | |||
return -1; | return -1; | |||
} | } | |||
string_t *query = t_str_new(256); | string_t *query = t_str_new(256); | |||
ARRAY_TYPE(sql_dict_param) params; | ARRAY_TYPE(sql_dict_param) params; | |||
t_array_init(¶ms, 4); | t_array_init(¶ms, 4); | |||
str_printfa(query, "SELECT %s FROM %s", | str_printfa(query, "SELECT %s FROM %s", | |||
map->value_field, map->table); | map->value_field, map->table); | |||
if (sql_dict_where_build(dict, map, &pattern_values, | if (sql_dict_where_build(set->username, map, &pattern_values, | |||
key[0] == DICT_PATH_PRIVATE[0], | key[0] == DICT_PATH_PRIVATE[0], | |||
SQL_DICT_RECURSE_NONE, query, | SQL_DICT_RECURSE_NONE, query, | |||
¶ms, &error) < 0) { | ¶ms, &error) < 0) { | |||
*error_r = t_strdup_printf( | *error_r = t_strdup_printf( | |||
"sql dict lookup: Failed to lookup key %s: %s", key, erro r); | "sql dict lookup: Failed to lookup key %s: %s", key, erro r); | |||
return -1; | return -1; | |||
} | } | |||
*stmt_r = sql_dict_statement_init(dict, str_c(query), ¶ms); | *stmt_r = sql_dict_statement_init(dict, str_c(query), ¶ms); | |||
return 0; | return 0; | |||
} | } | |||
skipping to change at line 522 | skipping to change at line 529 | |||
struct sql_result *result, unsigned int result_idx , | struct sql_result *result, unsigned int result_idx , | |||
unsigned int sql_field_idx) | unsigned int sql_field_idx) | |||
{ | { | |||
const struct dict_sql_field *sql_field; | const struct dict_sql_field *sql_field; | |||
sql_field = array_idx(&map->pattern_fields, sql_field_idx); | sql_field = array_idx(&map->pattern_fields, sql_field_idx); | |||
return sql_dict_result_unescape(sql_field->value_type, pool, | return sql_dict_result_unescape(sql_field->value_type, pool, | |||
result, result_idx); | result, result_idx); | |||
} | } | |||
static int sql_dict_lookup(struct dict *_dict, pool_t pool, const char *key, | static int sql_dict_lookup(struct dict *_dict, const struct dict_op_settings *se | |||
t, | ||||
pool_t pool, const char *key, | ||||
const char **value_r, const char **error_r) | const char **value_r, const char **error_r) | |||
{ | { | |||
struct sql_dict *dict = (struct sql_dict *)_dict; | struct sql_dict *dict = (struct sql_dict *)_dict; | |||
const struct dict_sql_map *map; | const struct dict_sql_map *map; | |||
struct sql_statement *stmt; | struct sql_statement *stmt; | |||
struct sql_result *result = NULL; | struct sql_result *result = NULL; | |||
int ret; | int ret; | |||
*value_r = NULL; | *value_r = NULL; | |||
if (sql_lookup_get_query(dict, key, &map, &stmt, error_r) < 0) | if (sql_lookup_get_query(dict, set, key, &map, &stmt, error_r) < 0) | |||
return -1; | return -1; | |||
result = sql_statement_query_s(&stmt); | result = sql_statement_query_s(&stmt); | |||
ret = sql_result_next_row(result); | ret = sql_result_next_row(result); | |||
if (ret < 0) { | if (ret < 0) { | |||
*error_r = t_strdup_printf("dict sql lookup failed: %s", | *error_r = t_strdup_printf("dict sql lookup failed: %s", | |||
sql_result_get_error(result)); | sql_result_get_error(result)); | |||
} else if (ret > 0) { | } else if (ret > 0) { | |||
*value_r = sql_dict_result_unescape_value(map, pool, result); | *value_r = sql_dict_result_unescape_value(map, pool, result); | |||
} | } | |||
skipping to change at line 582 | skipping to change at line 590 | |||
wanted. */ | wanted. */ | |||
result.ret = 0; | result.ret = 0; | |||
} | } | |||
} | } | |||
ctx->callback(&result, ctx->context); | ctx->callback(&result, ctx->context); | |||
i_free(ctx); | i_free(ctx); | |||
} | } | |||
static void | static void | |||
sql_dict_lookup_async(struct dict *_dict, const char *key, | sql_dict_lookup_async(struct dict *_dict, | |||
const struct dict_op_settings *set, | ||||
const char *key, | ||||
dict_lookup_callback_t *callback, void *context) | dict_lookup_callback_t *callback, void *context) | |||
{ | { | |||
struct sql_dict *dict = (struct sql_dict *)_dict; | struct sql_dict *dict = (struct sql_dict *)_dict; | |||
const struct dict_sql_map *map; | const struct dict_sql_map *map; | |||
struct sql_dict_lookup_context *ctx; | struct sql_dict_lookup_context *ctx; | |||
struct sql_statement *stmt; | struct sql_statement *stmt; | |||
const char *error; | const char *error; | |||
if (sql_lookup_get_query(dict, key, &map, &stmt, &error) < 0) { | if (sql_lookup_get_query(dict, set, key, &map, &stmt, &error) < 0) { | |||
struct dict_lookup_result result; | struct dict_lookup_result result; | |||
i_zero(&result); | i_zero(&result); | |||
result.ret = -1; | result.ret = -1; | |||
result.error = error; | result.error = error; | |||
callback(&result, context); | callback(&result, context); | |||
} else { | } else { | |||
ctx = i_new(struct sql_dict_lookup_context, 1); | ctx = i_new(struct sql_dict_lookup_context, 1); | |||
ctx->callback = callback; | ctx->callback = callback; | |||
ctx->context = context; | ctx->context = context; | |||
skipping to change at line 620 | skipping to change at line 630 | |||
{ | { | |||
struct sql_dict *dict = (struct sql_dict *)ctx->ctx.dict; | struct sql_dict *dict = (struct sql_dict *)ctx->ctx.dict; | |||
const struct dict_sql_map *maps; | const struct dict_sql_map *maps; | |||
unsigned int i, count; | unsigned int i, count; | |||
size_t pat_len, path_len; | size_t pat_len, path_len; | |||
bool recurse = (ctx->flags & DICT_ITERATE_FLAG_RECURSE) != 0; | bool recurse = (ctx->flags & DICT_ITERATE_FLAG_RECURSE) != 0; | |||
t_array_init(pattern_values, dict->set->max_pattern_fields_count); | t_array_init(pattern_values, dict->set->max_pattern_fields_count); | |||
maps = array_get(&dict->set->maps, &count); | maps = array_get(&dict->set->maps, &count); | |||
for (i = ctx->next_map_idx; i < count; i++) { | for (i = ctx->next_map_idx; i < count; i++) { | |||
if (dict_sql_map_match(&maps[i], ctx->paths[ctx->path_idx], | if (dict_sql_map_match(&maps[i], ctx->path, | |||
pattern_values, &pat_len, &path_len, | pattern_values, &pat_len, &path_len, | |||
TRUE, recurse) && | TRUE, recurse) && | |||
(recurse || | (recurse || | |||
array_count(pattern_values)+1 >= array_count(&maps[i].patter n_fields))) { | array_count(pattern_values)+1 >= array_count(&maps[i].patter n_fields))) { | |||
ctx->key_prefix_len = path_len; | ctx->key_prefix_len = path_len; | |||
ctx->pattern_prefix_len = pat_len; | ctx->pattern_prefix_len = pat_len; | |||
ctx->next_map_idx = i + 1; | ctx->next_map_idx = i + 1; | |||
str_truncate(ctx->key, 0); | str_truncate(ctx->key, 0); | |||
str_append(ctx->key, ctx->paths[ctx->path_idx]); | str_append(ctx->key, ctx->path); | |||
return &maps[i]; | 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, pattern_values); | ||||
return NULL; | return NULL; | |||
} | } | |||
static int | static int | |||
sql_dict_iterate_build_next_query(struct sql_dict_iterate_context *ctx, | sql_dict_iterate_build_next_query(struct sql_dict_iterate_context *ctx, | |||
struct sql_statement **stmt_r, | struct sql_statement **stmt_r, | |||
const char **error_r) | const char **error_r) | |||
{ | { | |||
struct sql_dict *dict = (struct sql_dict *)ctx->ctx.dict; | struct sql_dict *dict = (struct sql_dict *)ctx->ctx.dict; | |||
const struct dict_op_settings_private *set = &ctx->ctx.set; | ||||
const struct dict_sql_map *map; | const struct dict_sql_map *map; | |||
ARRAY_TYPE(const_string) pattern_values; | ARRAY_TYPE(const_string) pattern_values; | |||
const struct dict_sql_field *pattern_fields; | const struct dict_sql_field *pattern_fields; | |||
enum sql_recurse_type recurse_type; | enum sql_recurse_type recurse_type; | |||
unsigned int i, count; | unsigned int i, count; | |||
map = sql_dict_iterate_find_next_map(ctx, &pattern_values); | map = sql_dict_iterate_find_next_map(ctx, &pattern_values); | |||
/* NULL map is allowed if we have already done some lookups */ | /* NULL map is allowed if we have already done some lookups */ | |||
if (map == NULL) { | if (map == NULL) { | |||
if (!ctx->allow_null_map) { | if (!ctx->allow_null_map) { | |||
skipping to change at line 699 | skipping to change at line 705 | |||
if ((ctx->flags & DICT_ITERATE_FLAG_RECURSE) != 0) | if ((ctx->flags & DICT_ITERATE_FLAG_RECURSE) != 0) | |||
recurse_type = SQL_DICT_RECURSE_FULL; | recurse_type = SQL_DICT_RECURSE_FULL; | |||
else if ((ctx->flags & DICT_ITERATE_FLAG_EXACT_KEY) != 0) | else if ((ctx->flags & DICT_ITERATE_FLAG_EXACT_KEY) != 0) | |||
recurse_type = SQL_DICT_RECURSE_NONE; | recurse_type = SQL_DICT_RECURSE_NONE; | |||
else | else | |||
recurse_type = SQL_DICT_RECURSE_ONE; | recurse_type = SQL_DICT_RECURSE_ONE; | |||
ARRAY_TYPE(sql_dict_param) params; | ARRAY_TYPE(sql_dict_param) params; | |||
t_array_init(¶ms, 4); | t_array_init(¶ms, 4); | |||
bool add_username = (ctx->paths[ctx->path_idx][0] == DICT_PATH_PRIVATE[0] | bool add_username = (ctx->path[0] == DICT_PATH_PRIVATE[0]); | |||
); | if (sql_dict_where_build(set->username, map, &pattern_values, add_usernam | |||
if (sql_dict_where_build(dict, map, &pattern_values, add_username, | e, | |||
recurse_type, query, ¶ms, error_r) < 0) | recurse_type, query, ¶ms, error_r) < 0) | |||
return -1; | return -1; | |||
if ((ctx->flags & DICT_ITERATE_FLAG_SORT_BY_KEY) != 0) { | if ((ctx->flags & DICT_ITERATE_FLAG_SORT_BY_KEY) != 0) { | |||
str_append(query, " ORDER BY "); | str_append(query, " ORDER BY "); | |||
for (i = 0; i < count; i++) { | for (i = 0; i < count; i++) { | |||
str_printfa(query, "%s", pattern_fields[i].name); | str_printfa(query, "%s", pattern_fields[i].name); | |||
if (i < count-1) | if (i < count-1) | |||
str_append_c(query, ','); | str_append_c(query, ','); | |||
} | } | |||
skipping to change at line 743 | skipping to change at line 749 | |||
} | } | |||
pool_t pool_copy = ctx->pool; | pool_t pool_copy = ctx->pool; | |||
pool_unref(&pool_copy); | pool_unref(&pool_copy); | |||
} | } | |||
static int sql_dict_iterate_next_query(struct sql_dict_iterate_context *ctx) | static int sql_dict_iterate_next_query(struct sql_dict_iterate_context *ctx) | |||
{ | { | |||
struct sql_statement *stmt; | struct sql_statement *stmt; | |||
const char *error; | const char *error; | |||
unsigned int path_idx = ctx->path_idx; | ||||
int ret; | int ret; | |||
ret = sql_dict_iterate_build_next_query(ctx, &stmt, &error); | ret = sql_dict_iterate_build_next_query(ctx, &stmt, &error); | |||
if (ret <= 0) { | if (ret <= 0) { | |||
/* this is expected error */ | /* this is expected error */ | |||
if (ret == 0) | if (ret == 0) | |||
return ret; | return ret; | |||
/* failed */ | /* failed */ | |||
ctx->error = p_strdup_printf(ctx->pool, | ctx->error = p_strdup_printf(ctx->pool, | |||
"sql dict iterate failed for %s: %s", | "sql dict iterate failed for %s: %s", | |||
ctx->paths[path_idx], error); | ctx->path, error); | |||
return -1; | return -1; | |||
} | } | |||
if ((ctx->flags & DICT_ITERATE_FLAG_ASYNC) == 0) { | if ((ctx->flags & DICT_ITERATE_FLAG_ASYNC) == 0) { | |||
ctx->result = sql_statement_query_s(&stmt); | ctx->result = sql_statement_query_s(&stmt); | |||
} else { | } else { | |||
i_assert(ctx->result == NULL); | i_assert(ctx->result == NULL); | |||
ctx->synchronous_result = TRUE; | ctx->synchronous_result = TRUE; | |||
pool_ref(ctx->pool); | pool_ref(ctx->pool); | |||
sql_statement_query(&stmt, sql_dict_iterate_callback, ctx); | sql_statement_query(&stmt, sql_dict_iterate_callback, ctx); | |||
ctx->synchronous_result = FALSE; | ctx->synchronous_result = FALSE; | |||
} | } | |||
return ret; | return ret; | |||
} | } | |||
static struct dict_iterate_context * | static struct dict_iterate_context * | |||
sql_dict_iterate_init(struct dict *_dict, const char *const *paths, | sql_dict_iterate_init(struct dict *_dict, | |||
enum dict_iterate_flags flags) | const struct dict_op_settings *set ATTR_UNUSED, | |||
const char *path, enum dict_iterate_flags flags) | ||||
{ | { | |||
struct sql_dict_iterate_context *ctx; | struct sql_dict_iterate_context *ctx; | |||
unsigned int i, path_count; | ||||
pool_t pool; | pool_t pool; | |||
pool = pool_alloconly_create("sql dict iterate", 512); | pool = pool_alloconly_create("sql dict iterate", 512); | |||
ctx = p_new(pool, struct sql_dict_iterate_context, 1); | ctx = p_new(pool, struct sql_dict_iterate_context, 1); | |||
ctx->ctx.dict = _dict; | ctx->ctx.dict = _dict; | |||
ctx->pool = pool; | ctx->pool = pool; | |||
ctx->flags = flags; | ctx->flags = flags; | |||
for (path_count = 0; paths[path_count] != NULL; path_count++) ; | ctx->path = p_strdup(pool, path); | |||
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); | ctx->key = str_new(pool, 256); | |||
return &ctx->ctx; | return &ctx->ctx; | |||
} | } | |||
static bool sql_dict_iterate(struct dict_iterate_context *_ctx, | static bool sql_dict_iterate(struct dict_iterate_context *_ctx, | |||
const char **key_r, const char *const **values_r) | const char **key_r, const char *const **values_r) | |||
{ | { | |||
struct sql_dict_iterate_context *ctx = | struct sql_dict_iterate_context *ctx = | |||
(struct sql_dict_iterate_context *)_ctx; | (struct sql_dict_iterate_context *)_ctx; | |||
skipping to change at line 1098 | skipping to change at line 1100 | |||
if (sql_dict_value_get(fields[i].map, | if (sql_dict_value_get(fields[i].map, | |||
value_type, "value", fields[i].value, | value_type, "value", fields[i].value, | |||
"", ¶ms, error_r) < 0) | "", ¶ms, error_r) < 0) | |||
return -1; | return -1; | |||
} | } | |||
if (build->add_username) { | if (build->add_username) { | |||
struct sql_dict_param *param = array_append_space(¶ms); | struct sql_dict_param *param = array_append_space(¶ms); | |||
str_printfa(prefix, ",%s", fields[0].map->username_field); | str_printfa(prefix, ",%s", fields[0].map->username_field); | |||
str_append(suffix, ",?"); | str_append(suffix, ",?"); | |||
param->value_type = DICT_SQL_TYPE_STRING; | param->value_type = DICT_SQL_TYPE_STRING; | |||
param->value_str = dict->username; | param->value_str = ctx->ctx.set.username; | |||
} | } | |||
/* add the variable fields that were parsed from the path */ | /* add the variable fields that were parsed from the path */ | |||
pattern_fields = array_get(&fields[0].map->pattern_fields, &count); | pattern_fields = array_get(&fields[0].map->pattern_fields, &count); | |||
pattern_values = array_get(build->pattern_values, &count2); | pattern_values = array_get(build->pattern_values, &count2); | |||
i_assert(count == count2); | i_assert(count == count2); | |||
for (i = 0; i < count; i++) { | for (i = 0; i < count; i++) { | |||
str_printfa(prefix, ",%s", pattern_fields[i].name); | str_printfa(prefix, ",%s", pattern_fields[i].name); | |||
str_append(suffix, ",?"); | str_append(suffix, ",?"); | |||
if (sql_dict_field_get_value(fields[0].map, &pattern_fields[i], | if (sql_dict_field_get_value(fields[0].map, &pattern_fields[i], | |||
skipping to change at line 1163 | skipping to change at line 1165 | |||
value_type, "value", fields[i].value, | value_type, "value", fields[i].value, | |||
"", ¶ms, error_r) < 0) | "", ¶ms, error_r) < 0) | |||
return -1; | return -1; | |||
} | } | |||
*stmt_r = sql_dict_transaction_stmt_init(ctx, str_c(prefix), ¶ms); | *stmt_r = sql_dict_transaction_stmt_init(ctx, str_c(prefix), ¶ms); | |||
return 0; | return 0; | |||
} | } | |||
static int | static int | |||
sql_dict_update_query(const struct dict_sql_build_query *build, | sql_dict_update_query(const struct dict_sql_build_query *build, | |||
const struct dict_op_settings_private *set, | ||||
const char **query_r, ARRAY_TYPE(sql_dict_param) *params, | const char **query_r, ARRAY_TYPE(sql_dict_param) *params, | |||
const char **error_r) | const char **error_r) | |||
{ | { | |||
struct sql_dict *dict = build->dict; | ||||
const struct dict_sql_build_query_field *fields; | const struct dict_sql_build_query_field *fields; | |||
unsigned int i, field_count; | unsigned int i, field_count; | |||
string_t *query; | string_t *query; | |||
fields = array_get(&build->fields, &field_count); | fields = array_get(&build->fields, &field_count); | |||
i_assert(field_count > 0); | i_assert(field_count > 0); | |||
query = t_str_new(64); | query = t_str_new(64); | |||
str_printfa(query, "UPDATE %s SET ", fields[0].map->table); | str_printfa(query, "UPDATE %s SET ", fields[0].map->table); | |||
for (i = 0; i < field_count; i++) { | for (i = 0; i < field_count; i++) { | |||
const char *first_value_field = | const char *first_value_field = | |||
t_strcut(fields[i].map->value_field, ','); | t_strcut(fields[i].map->value_field, ','); | |||
if (i > 0) | if (i > 0) | |||
str_append_c(query, ','); | str_append_c(query, ','); | |||
str_printfa(query, "%s=%s+?", first_value_field, | str_printfa(query, "%s=%s+?", first_value_field, | |||
first_value_field); | first_value_field); | |||
} | } | |||
if (sql_dict_where_build(dict, fields[0].map, build->pattern_values, | if (sql_dict_where_build(set->username, fields[0].map, build->pattern_val ues, | |||
build->add_username, SQL_DICT_RECURSE_NONE, | build->add_username, SQL_DICT_RECURSE_NONE, | |||
query, params, error_r) < 0) | query, params, error_r) < 0) | |||
return -1; | return -1; | |||
*query_r = str_c(query); | *query_r = str_c(query); | |||
return 0; | return 0; | |||
} | } | |||
static void sql_dict_prev_set_free(struct sql_dict_transaction_context *ctx) | static void sql_dict_prev_set_free(struct sql_dict_transaction_context *ctx) | |||
{ | { | |||
struct sql_dict_prev *prev_set; | struct sql_dict_prev *prev_set; | |||
skipping to change at line 1265 | skipping to change at line 1267 | |||
} | } | |||
sql_dict_prev_set_free(ctx); | sql_dict_prev_set_free(ctx); | |||
} | } | |||
static void sql_dict_unset(struct dict_transaction_context *_ctx, | static void sql_dict_unset(struct dict_transaction_context *_ctx, | |||
const char *key) | const char *key) | |||
{ | { | |||
struct sql_dict_transaction_context *ctx = | struct sql_dict_transaction_context *ctx = | |||
(struct sql_dict_transaction_context *)_ctx; | (struct sql_dict_transaction_context *)_ctx; | |||
struct sql_dict *dict = (struct sql_dict *)_ctx->dict; | struct sql_dict *dict = (struct sql_dict *)_ctx->dict; | |||
const struct dict_op_settings_private *set = &_ctx->set; | ||||
const struct dict_sql_map *map; | const struct dict_sql_map *map; | |||
ARRAY_TYPE(const_string) pattern_values; | ARRAY_TYPE(const_string) pattern_values; | |||
string_t *query = t_str_new(256); | string_t *query = t_str_new(256); | |||
ARRAY_TYPE(sql_dict_param) params; | ARRAY_TYPE(sql_dict_param) params; | |||
const char *error; | const char *error; | |||
if (ctx->error != NULL) | if (ctx->error != NULL) | |||
return; | return; | |||
/* In theory we could unset one of the previous set/incs in this | /* In theory we could unset one of the previous set/incs in this | |||
skipping to change at line 1289 | skipping to change at line 1292 | |||
sql_dict_prev_set_flush(ctx); | sql_dict_prev_set_flush(ctx); | |||
map = sql_dict_find_map(dict, key, &pattern_values); | map = sql_dict_find_map(dict, key, &pattern_values); | |||
if (map == NULL) { | if (map == NULL) { | |||
ctx->error = i_strdup_printf("dict-sql: Invalid/unmapped key: %s" , key); | ctx->error = i_strdup_printf("dict-sql: Invalid/unmapped key: %s" , key); | |||
return; | return; | |||
} | } | |||
str_printfa(query, "DELETE FROM %s", map->table); | str_printfa(query, "DELETE FROM %s", map->table); | |||
t_array_init(¶ms, 4); | t_array_init(¶ms, 4); | |||
if (sql_dict_where_build(dict, map, &pattern_values, | if (sql_dict_where_build(set->username, map, &pattern_values, | |||
key[0] == DICT_PATH_PRIVATE[0], | key[0] == DICT_PATH_PRIVATE[0], | |||
SQL_DICT_RECURSE_NONE, query, | SQL_DICT_RECURSE_NONE, query, | |||
¶ms, &error) < 0) { | ¶ms, &error) < 0) { | |||
ctx->error = i_strdup_printf( | ctx->error = i_strdup_printf( | |||
"dict-sql: Failed to delete %s: %s", key, error); | "dict-sql: Failed to delete %s: %s", key, error); | |||
} else { | } else { | |||
struct sql_statement *stmt = | struct sql_statement *stmt = | |||
sql_dict_transaction_stmt_init(ctx, str_c(query), ¶ms ); | sql_dict_transaction_stmt_init(ctx, str_c(query), ¶ms ); | |||
sql_update_stmt(ctx->sql_ctx, &stmt); | sql_update_stmt(ctx->sql_ctx, &stmt); | |||
} | } | |||
skipping to change at line 1330 | skipping to change at line 1333 | |||
struct sql_dict_prev *prev_inc; | struct sql_dict_prev *prev_inc; | |||
array_foreach_modifiable(&ctx->prev_inc, prev_inc) | array_foreach_modifiable(&ctx->prev_inc, prev_inc) | |||
i_free(prev_inc->key); | i_free(prev_inc->key); | |||
array_free(&ctx->prev_inc); | array_free(&ctx->prev_inc); | |||
} | } | |||
static void sql_dict_prev_inc_flush(struct sql_dict_transaction_context *ctx) | static void sql_dict_prev_inc_flush(struct sql_dict_transaction_context *ctx) | |||
{ | { | |||
struct sql_dict *dict = (struct sql_dict *)ctx->ctx.dict; | struct sql_dict *dict = (struct sql_dict *)ctx->ctx.dict; | |||
const struct dict_op_settings_private *set = &ctx->ctx.set; | ||||
const struct sql_dict_prev *prev_incs; | const struct sql_dict_prev *prev_incs; | |||
unsigned int count; | unsigned int count; | |||
ARRAY_TYPE(const_string) pattern_values; | ARRAY_TYPE(const_string) pattern_values; | |||
struct dict_sql_build_query build; | struct dict_sql_build_query build; | |||
struct dict_sql_build_query_field *field; | struct dict_sql_build_query_field *field; | |||
ARRAY_TYPE(sql_dict_param) params; | ARRAY_TYPE(sql_dict_param) params; | |||
struct sql_dict_param *param; | struct sql_dict_param *param; | |||
const char *query, *error; | const char *query, *error; | |||
i_assert(array_is_created(&ctx->prev_inc)); | i_assert(array_is_created(&ctx->prev_inc)); | |||
skipping to change at line 1380 | skipping to change at line 1384 | |||
(prev_incs[i].key[0] == DICT_PATH_PRIVATE[0])); | (prev_incs[i].key[0] == DICT_PATH_PRIVATE[0])); | |||
field = array_append_space(&build.fields); | field = array_append_space(&build.fields); | |||
field->map = prev_incs[i].map; | field->map = prev_incs[i].map; | |||
field->value = NULL; /* unused */ | field->value = NULL; /* unused */ | |||
param = array_append_space(¶ms); | param = array_append_space(¶ms); | |||
param->value_type = DICT_SQL_TYPE_INT; | param->value_type = DICT_SQL_TYPE_INT; | |||
param->value_int64 = prev_incs[i].value.diff; | param->value_int64 = prev_incs[i].value.diff; | |||
} | } | |||
if (sql_dict_update_query(&build, &query, ¶ms, &error) < 0) { | if (sql_dict_update_query(&build, set, &query, ¶ms, &error) < 0) { | |||
ctx->error = i_strdup_printf( | ctx->error = i_strdup_printf( | |||
"dict-sql: Failed to increase %u fields (first %s): %s", | "dict-sql: Failed to increase %u fields (first %s): %s", | |||
count, prev_incs[0].key, error); | count, prev_incs[0].key, error); | |||
} else { | } else { | |||
struct sql_statement *stmt = | struct sql_statement *stmt = | |||
sql_dict_transaction_stmt_init(ctx, query, ¶ms); | sql_dict_transaction_stmt_init(ctx, query, ¶ms); | |||
sql_update_stmt_get_rows(ctx->sql_ctx, &stmt, | sql_update_stmt_get_rows(ctx->sql_ctx, &stmt, | |||
sql_dict_next_inc_row(ctx)); | sql_dict_next_inc_row(ctx)); | |||
} | } | |||
sql_dict_prev_inc_free(ctx); | sql_dict_prev_inc_free(ctx); | |||
End of changes. 32 change blocks. | ||||
37 lines changed or deleted | 43 lines changed or added |