Mercurial > dovecot > core-2.2
changeset 19473:836a0c2bc48a
lib-storage: mail_search_args_simplify() handles now "(a AND b) OR (a AND c)" -> "a AND (b OR c)"
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sun, 06 Dec 2015 18:14:08 +0200 |
parents | 8749308aad53 |
children | 7c984bcb5f57 |
files | src/lib-storage/mail-search-args-simplify.c src/lib-storage/test-mail-search-args-simplify.c |
diffstat | 2 files changed, 111 insertions(+), 5 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-storage/mail-search-args-simplify.c Sun Dec 06 18:12:24 2015 +0200 +++ b/src/lib-storage/mail-search-args-simplify.c Sun Dec 06 18:14:08 2015 +0200 @@ -278,6 +278,37 @@ } static bool +mail_search_args_remove_equal(struct mail_search_arg *parent_arg, + const struct mail_search_arg *wanted_arg, + bool check_subs) +{ + struct mail_search_arg **argp; + bool found = FALSE; + + for (argp = &parent_arg->value.subargs; (*argp) != NULL; ) { + if (mail_search_arg_one_equals(*argp, wanted_arg)) { + *argp = (*argp)->next; + found = TRUE; + } else if (check_subs) { + i_assert((*argp)->type == SEARCH_SUB); + if (!mail_search_args_remove_equal(*argp, wanted_arg, FALSE)) { + /* we already verified that this should have + existed. */ + i_unreached(); + } + if ((*argp)->value.subargs == NULL) + *argp = (*argp)->next; + else + argp = &(*argp)->next; + found = TRUE; + } else { + argp = &(*argp)->next; + } + } + return found; +} + +static bool mail_search_args_have_all_equal(struct mail_search_arg *parent_arg, const struct mail_search_arg *wanted_args) { @@ -341,7 +372,66 @@ } static bool -mail_search_args_simplify_sub(struct mailbox *box, +mail_search_args_simplify_extract_common_and(struct mail_search_arg *parent_arg, + pool_t pool) +{ + struct mail_search_arg *arg, *sub_arg, *sub_next; + struct mail_search_arg *or_arg, *common_args = NULL; + + i_assert(parent_arg->type == SEARCH_OR); + i_assert(!parent_arg->match_not); + + /* find the first SEARCH_SUB */ + for (arg = parent_arg->value.subargs; arg != NULL; arg = arg->next) { + if (arg->type == SEARCH_SUB) + break; + } + if (arg == NULL) + return FALSE; + + for (sub_arg = arg->value.subargs; sub_arg != NULL; sub_arg = sub_next) { + sub_next = sub_arg->next; + + /* check if sub_arg is found from all the args */ + for (arg = parent_arg->value.subargs; arg != NULL; arg = arg->next) { + if (mail_search_arg_one_equals(arg, sub_arg)) { + /* the whole arg matches */ + } else if (arg->type == SEARCH_SUB && + mail_search_args_have_equal(arg->value.subargs, sub_arg)) { + /* exists as subarg */ + } else { + break; + } + } + if (arg != NULL) + continue; + + /* extract the arg and put it to common_args */ + mail_search_args_remove_equal(parent_arg, sub_arg, TRUE); + sub_arg->next = common_args; + common_args = sub_arg; + } + if (common_args == NULL) + return FALSE; + + if (parent_arg->value.subargs == NULL) { + /* there are only common args */ + parent_arg->type = SEARCH_SUB; + parent_arg->value.subargs = common_args; + } else { + /* replace OR arg with AND(common_args, OR(non_common_args)) */ + or_arg = p_new(pool, struct mail_search_arg, 1); + *or_arg = *parent_arg; + or_arg->next = common_args; + + parent_arg->type = SEARCH_SUB; + parent_arg->value.subargs = or_arg; + } + return TRUE; +} + +static bool +mail_search_args_simplify_sub(struct mailbox *box, pool_t pool, struct mail_search_arg *args, bool parent_and) { struct mail_search_simplify_ctx ctx; @@ -390,8 +480,10 @@ if (args->type == SEARCH_OR) { if (mail_search_args_simplify_or_drop_redundent_args(args)) ctx.removals = TRUE; + if (mail_search_args_simplify_extract_common_and(args, pool)) + ctx.removals = TRUE; } - if (mail_search_args_simplify_sub(box, args->value.subargs, + if (mail_search_args_simplify_sub(box, pool, args->value.subargs, args->type != SEARCH_OR)) ctx.removals = TRUE; } @@ -513,12 +605,12 @@ args->simplified = TRUE; - removals = mail_search_args_simplify_sub(args->box, args->args, TRUE); + removals = mail_search_args_simplify_sub(args->box, args->pool, args->args, TRUE); if (mail_search_args_unnest_inthreads(args, &args->args, FALSE, TRUE)) { /* we may have added some extra SUBs that could be dropped */ - mail_search_args_simplify_sub(args->box, args->args, TRUE); + mail_search_args_simplify_sub(args->box, args->pool, args->args, TRUE); } while (removals) - removals = mail_search_args_simplify_sub(args->box, args->args, TRUE); + removals = mail_search_args_simplify_sub(args->box, args->pool, args->args, TRUE); }
--- a/src/lib-storage/test-mail-search-args-simplify.c Sun Dec 06 18:12:24 2015 +0200 +++ b/src/lib-storage/test-mail-search-args-simplify.c Sun Dec 06 18:14:08 2015 +0200 @@ -102,6 +102,20 @@ { "OR TEXT common1 ( TEXT common1 TEXT unique1 )", "TEXT common1" }, { "OR TEXT common1 ( TEXT unique1 TEXT common1 )", "TEXT common1" }, { "OR TEXT common1 OR ( TEXT unique1 TEXT common1 ) ( TEXT unique3 TEXT common1 )", "TEXT common1" }, + + { "OR ( TEXT common1 TEXT unique1 ) ( TEXT common1 TEXT unique2 )", "(OR TEXT unique1 TEXT unique2) TEXT common1" }, + { "OR ( TEXT unique1 TEXT common1 ) ( TEXT unique2 TEXT common1 )", "(OR TEXT unique1 TEXT unique2) TEXT common1" }, + { "OR ( TEXT common1 TEXT unique1 ) ( TEXT unique2 TEXT common1 )", "(OR TEXT unique1 TEXT unique2) TEXT common1" }, + { "OR ( TEXT unique1 TEXT common1 ) ( TEXT common1 TEXT unique2 )", "(OR TEXT unique1 TEXT unique2) TEXT common1" }, + + { "OR ( TEXT unique1 TEXT common1 ) ( TEXT common1 TEXT unique2 TEXT unique3 )", "(OR TEXT unique1 (TEXT unique2 TEXT unique3)) TEXT common1" }, + { "OR ( TEXT common1 TEXT common2 TEXT unique1 ) ( TEXT common1 TEXT common2 TEXT unique2 )", "(OR TEXT unique1 TEXT unique2) TEXT common2 TEXT common1" }, + { "OR ( TEXT common1 TEXT common2 TEXT unique1 TEXT unique2 ) ( TEXT common1 TEXT common2 TEXT unique3 TEXT unique4 )", "(OR (TEXT unique1 TEXT unique2) (TEXT unique3 TEXT unique4)) TEXT common2 TEXT common1" }, + + { "OR ( TEXT unique1 TEXT unique2 ) TEXT unique3", "(OR (TEXT unique1 TEXT unique2) TEXT unique3)" }, + { "OR ( TEXT unique1 TEXT unique2 ) ( TEXT unique3 TEXT unique4 )", "(OR (TEXT unique1 TEXT unique2) (TEXT unique3 TEXT unique4))" }, + { "OR ( TEXT common1 TEXT unique1 ) OR ( TEXT common1 TEXT unique2 ) TEXT unique3", "(OR (TEXT common1 TEXT unique1) OR (TEXT common1 TEXT unique2) TEXT unique3)" }, + { "OR ( TEXT common1 TEXT unique1 ) OR ( TEXT common1 TEXT common2 ) ( TEXT common2 TEXT unique2 )", "(OR (TEXT common1 TEXT unique1) OR (TEXT common1 TEXT common2) (TEXT common2 TEXT unique2))" }, }; static struct mail_search_args *