return NULL;
}
+static bool
+dict_sql_value_type_parse(const char *value_type, enum dict_sql_type *type_r)
+{
+ if (strcmp(value_type, "string") == 0)
+ *type_r = DICT_SQL_TYPE_STRING;
+ else if (strcmp(value_type, "hexblob") == 0)
+ *type_r = DICT_SQL_TYPE_HEXBLOB;
+ else if (strcmp(value_type, "uint") == 0)
+ *type_r = DICT_SQL_TYPE_UINT;
+ else
+ return FALSE;
+ return TRUE;
+}
+
static const char *dict_sql_map_finish(struct setting_parser_ctx *ctx)
{
+ unsigned int i;
+
if (ctx->cur_map.pattern == NULL)
return "Missing setting: pattern";
if (ctx->cur_map.table == NULL)
return "Missing setting: table";
if (ctx->cur_map.value_field == NULL)
return "Missing setting: value_field";
+
+ ctx->cur_map.value_fields = (const char *const *)
+ p_strsplit_spaces(ctx->pool, ctx->cur_map.value_field, ",");
+ ctx->cur_map.values_count = str_array_length(ctx->cur_map.value_fields);
+
+ enum dict_sql_type *value_types =
+ p_new(ctx->pool, enum dict_sql_type, ctx->cur_map.values_count);
if (ctx->cur_map.value_type != NULL) {
- if (strcmp(ctx->cur_map.value_type, "string") != 0 &&
- strcmp(ctx->cur_map.value_type, "hexblob") != 0 &&
- strcmp(ctx->cur_map.value_type, "uint") != 0)
- return "Invalid value in value_type";
+ const char *const *types =
+ t_strsplit_spaces(ctx->cur_map.value_type, ",");
+ if (str_array_length(types) != ctx->cur_map.values_count)
+ return "Number of fields in value_fields doesn't match value_type";
+ for (i = 0; i < ctx->cur_map.values_count; i++) {
+ if (!dict_sql_value_type_parse(types[i], &value_types[i]))
+ return "Invalid value in value_type";
+ }
+ } else {
+ for (i = 0; i < ctx->cur_map.values_count; i++) {
+ value_types[i] = ctx->cur_map.value_hexblob ?
+ DICT_SQL_TYPE_HEXBLOB : DICT_SQL_TYPE_STRING;
+ }
}
+ ctx->cur_map.value_types = value_types;
if (ctx->cur_map.username_field == NULL) {
/* not all queries require this */
return str_c(str);
}
-static enum dict_sql_type
-sql_dict_map_type(const struct dict_sql_map *map)
-{
- if (map->value_type != NULL) {
- if (strcmp(map->value_type, "string") == 0)
- return DICT_SQL_TYPE_STRING;
- if (strcmp(map->value_type, "hexblob") == 0)
- return DICT_SQL_TYPE_HEXBLOB;
- if (strcmp(map->value_type, "uint") == 0)
- return DICT_SQL_TYPE_UINT;
- i_unreached(); /* should have checked already at parsing */
- }
- return map->value_hexblob ? DICT_SQL_TYPE_HEXBLOB : DICT_SQL_TYPE_STRING;
-}
-
static const char *
sql_dict_result_unescape_value(const struct dict_sql_map *map, pool_t pool,
struct sql_result *result)
{
- return sql_dict_result_unescape(sql_dict_map_type(map), pool, result, 0);
+ return sql_dict_result_unescape(map->value_types[0], pool, result, 0);
+}
+
+static const char *const *
+sql_dict_result_unescape_values(const struct dict_sql_map *map, pool_t pool,
+ struct sql_result *result)
+{
+ const char **values;
+ unsigned int i;
+
+ values = p_new(pool, const char *, map->values_count + 1);
+ for (i = 0; i < map->values_count; i++) {
+ values[i] = sql_dict_result_unescape(map->value_types[i],
+ pool, result, i);
+ }
+ return values;
}
static const char *
struct sql_dict_lookup_context *ctx)
{
struct dict_lookup_result result;
- const char *values[2] = { NULL, NULL };
i_zero(&result);
result.ret = sql_result_next_row(sql_result);
if (result.ret < 0)
result.error = sql_result_get_error(sql_result);
else if (result.ret > 0) {
- result.value = sql_dict_result_unescape_value(ctx->map,
+ result.values = sql_dict_result_unescape_values(ctx->map,
pool_datastack_create(), sql_result);
+ result.value = result.values[0];
if (result.value == NULL) {
/* NULL value returned. we'll treat this as
"not found", which is probably what is usually
wanted. */
result.ret = 0;
- } else {
- values[0] = result.value;
- result.values = values;
}
}
ctx->callback(&result, ctx->context);
str_append_c(prefix, ',');
str_append_c(suffix, ',');
}
- str_append(prefix, fields[i].map->value_field);
+ str_append(prefix, t_strcut(fields[i].map->value_field, ','));
if (build->inc)
str_append(suffix, fields[i].value);
else {
enum dict_sql_type value_type =
- sql_dict_map_type(fields[i].map);
+ fields[i].map->value_types[0];
if (sql_dict_value_escape(suffix, dict, fields[i].map,
value_type, "value", fields[i].value,
"", error_r) < 0)
str_append(prefix, " ON DUPLICATE KEY UPDATE ");
for (i = 0; i < field_count; i++) {
+ const char *first_value_field =
+ t_strcut(fields[i].map->value_field, ',');
if (i > 0)
str_append_c(prefix, ',');
- str_append(prefix, fields[i].map->value_field);
+ str_append(prefix, first_value_field);
str_append_c(prefix, '=');
if (build->inc) {
str_printfa(prefix, "%s+%s",
- fields[i].map->value_field,
+ first_value_field,
fields[i].value);
} else {
enum dict_sql_type value_type =
- sql_dict_map_type(fields[i].map);
+ fields[i].map->value_types[0];
if (sql_dict_value_escape(prefix, dict, fields[i].map,
value_type, "value", fields[i].value,
"", error_r) < 0)
sql_dict_transaction_add_timestamp(ctx, query);
str_append(query, " SET ");
for (i = 0; i < field_count; i++) {
+ const char *first_value_field =
+ t_strcut(fields[i].map->value_field, ',');
if (i > 0)
str_append_c(query, ',');
- str_printfa(query, "%s=%s", fields[i].map->value_field,
- fields[i].map->value_field);
+ str_printfa(query, "%s=%s", first_value_field,
+ first_value_field);
if (fields[i].value[0] != '-')
str_append_c(query, '+');
str_append(query, fields[i].value);